1から作ると手間だけどレイアウトはこだわりたい、コピペメモ
練習にどうぞ。
一連の流れ
1.holderレイアウトを作成
2.data classを定義
3.recyclerviewをActivityレイアウトに置く
4.itemAdapterクラスを定義、List<data class>を繋ぐ
5.Recyclerview.adapterへ接続
手順は多いがやることは実に簡単。
なんとなくレイアウトとActivityの繋ぎがわかればいい。
1.holderレイアウトを作成
item_holder.xmlファイルを作成
文字、画像、チェックボックスなど様々なViewが使えるので自分好みにレイアウトしよう。
リストという繰り返されるレイアウトなのである程度の見やすさは必要。
layoutフォルダ上で右クリック > New > XML > LayoutXMLFile で追加。
imageはVectorAssetで作成
<vector android:height="80dp" android:tint="#29A19A"
android:viewportHeight="25" android:viewportWidth="25"
android:width="80dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M4,3h6v2h-6z"/>
<path android:fillColor="@android:color/white" android:pathData="M1,7h5v2h-5z"/>
<path android:fillColor="@android:color/white" android:pathData="M3,19h5v2h-5z"/>
<path android:fillColor="@android:color/white" android:pathData="M13.73,10.61c0.75,0.23 1.3,0.78 1.57,1.46l4.27,-7.11c0.65,-1.08 0.3,-2.48 -0.78,-3.13c-0.87,-0.52 -1.99,-0.41 -2.73,0.29l-3.43,3.21C12.23,5.7 12,6.23 12,6.78v3.93C12.36,10.56 12.98,10.38 13.73,10.61z"/>
<path android:fillColor="@android:color/white" android:pathData="M10.61,12.27c0.16,-0.52 0.48,-0.96 0.89,-1.27H3.28C2.02,11 1,12.02 1,13.28c0,1.02 0.67,1.91 1.65,2.19l4.51,1.29c0.53,0.15 1.1,0.08 1.58,-0.21l2.69,-1.61C10.66,14.32 10.3,13.27 10.61,12.27z"/>
<path android:fillColor="@android:color/white" android:pathData="M22.21,18.61l-2.28,-4.1c-0.27,-0.48 -0.73,-0.83 -1.26,-0.97l-3.18,-0.8c0.03,0.32 0,0.66 -0.1,0.99c-0.32,1.06 -1.28,1.77 -2.39,1.77c-0.61,0 -0.99,-0.22 -1,-0.22V21c-1.1,0 -2,0.9 -2,2h6c0,-1.1 -0.9,-2 -2,-2v-4.28l4.61,4.61c0.89,0.89 2.33,0.89 3.22,0C22.55,20.61 22.71,19.5 22.21,18.61z"/>
<path android:fillColor="@android:color/white" android:pathData="M12.56,14.43c0.79,0.24 1.63,-0.2 1.87,-1c0.24,-0.79 -0.2,-1.63 -1,-1.87c-0.79,-0.24 -1.63,0.2 -1.87,1C11.32,13.35 11.77,14.19 12.56,14.43z"/>
</vector>
枠線が欲しいのでborder.xmlを作成
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:state_selected="false"
android:state_pressed="false">
<shape>
<stroke
android:width="1dp"
android:color="#94A78E">
</stroke>
</shape>
</item>
</selector>
全体(色はcolors.xmlで登録)
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="80dp"
android:background="@drawable/border"
android:orientation="horizontal"
tools:ignore="MissingConstraints">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/darkslategray"
android:layout_weight="1"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="horizontal">
<ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:padding="5dp"
android:src="@drawable/baseline_wind_power_24" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical">
<TextView
android:id="@+id/textView_title"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="@drawable/border"
android:gravity="center"
android:text="title"
android:textColor="@color/darkslategray"
android:textSize="9dp"
android:textStyle="bold" />
<TextView
android:id="@+id/textView_date"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:background="@drawable/border"
android:gravity="center"
android:text="some"
android:textSize="9dp" />
</LinearLayout>
<TextView
android:id="@+id/textView_text"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2"
android:background="@drawable/border"
android:gravity="center"
android:text="text"
android:textSize="15dp" />
<CheckBox
android:id="@+id/checkBox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="0.5" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
レイアウトは分かりやすいこちらを参考(有難うございます)
2.data classを定義
画像の変更、チェックボックスの取得はコツがいるので後日。
data class ItemData(
val title:String,
val some:Date,
val text:String,
)
3.recyclerviewをActivityレイアウトに置く
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/darkslategray"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="15dp"
android:background="@color/white"
android:orientation="vertical">
<TextView
android:id="@+id/text_v"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:text="Hello World!" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="7"
tools:ignore="MissingConstraints">
</androidx.recyclerview.widget.RecyclerView>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
4.itemAdapterクラスを定義、List<data class>を繋ぐ
短い記述だが各種設定が詰まっている。
package com.example.myapplication
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import java.time.format.DateTimeFormatter
import java.util.Locale
//引数に注目しよう
class Adapter (private var rowDataList:MutableList<ItemData>):RecyclerView.Adapter<Adapter.ItemViewHolder>(){
//日付の描画フォーマット
private var format = DateTimeFormatter.ofPattern("MMMM",Locale.US)
//ここでitem_holder.xmlレイアウト(holder)がactivity_main.xmlのRecyclerViewに適合する(adapter)
class ItemViewHolder(itemView: View): RecyclerView.ViewHolder(itemView) {
val title: TextView = itemView.findViewById(R.id.textView_title)
val date: TextView = itemView.findViewById(R.id.textView_date)
val text: TextView = itemView.findViewById(R.id.textView_text)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ItemViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.item_holder,parent,false)
return ItemViewHolder(view)
}
override fun getItemCount(): Int = rowDataList.size
//List内容を描画する
override fun onBindViewHolder(holder: ItemViewHolder, position: Int) {
val rowData = rowDataList[position]
println(rowData)
holder.apply {
rowData.also {
title.text = it.title
date.text = format.format( it.some)
text.text = it.text
}
}
}
}
5.Recyclerview.adapterへ接続
忘れがちなRecyclerView.LayoutManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.example.myapplication.databinding.ActivityMainBinding
import java.time.LocalDate
import java.util.Date
class MainActivity : AppCompatActivity() {
private val local = LocalDate.now()
private var dataSet = mutableListOf<ItemData>()
private var itemAdapter:Adapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
//RecyclerViewで表示するアイテムの数を返す
binding.recyclerView.setHasFixedSize(true)
//recyclerview アダプタの接続準備
val layoutManager: RecyclerView.LayoutManager = LinearLayoutManager(this)
binding.recyclerView.layoutManager = layoutManager
}
private fun dateAdd(st:String,text:String):MutableList<ItemData>{
val item = ItemData(
st,
local.plusMonths( dataSet.size.toLong()),
text
)
dataSet.run {if(this.none { it == item })this.add(0,item)}
return dataSet
}
override fun onStart() {
super.onStart()
dateAdd("${dataSet.size}番目","AAAAAA")
dateAdd("${dataSet.size}番目","BBBBBB")
dateAdd("${dataSet.size}番目","CCCCCC")
//上記に入れたListをitemAdapterレイアウト設定でrecyclerviewアダプタに接続する
itemAdapter = Adapter(dataSet)
binding.recyclerView.adapter = itemAdapter
}
}
おまけ
増えている‼(onStart()で再び呼び出されたため)
ここでAdapterのprintln(rowData)でログを確認する。
//最初
ItemData(title=2番目, some=2025-01-28, text=CCCCCC)
ItemData(title=1番目, some=2024-12-28, text=BBBBBB)
ItemData(title=0番目, some=2024-11-28, text=AAAAAA)
//閉じたあと
ItemData(title=5番目, some=2025-04-28, text=CCCCCC)
ItemData(title=4番目, some=2025-03-28, text=BBBBBB)
ItemData(title=3番目, some=2025-02-28, text=AAAAAA)
ItemData(title=2番目, some=2025-01-28, text=CCCCCC)
ItemData(title=1番目, some=2024-12-28, text=BBBBBB)
ItemData(title=0番目, some=2024-11-28, text=AAAAAA)
それぞれ一度だけ呼ばれている。
下記を入れれば任意のタイミングでリスト更新ができるはずだ。
itemAdapter = Adapter(dataSet)//dataSetの変更があれば
binding.recyclerView.adapter = itemAdapter//反映させる