RecyclerViewを扱う
RecyclerViewを使ってコンテンツ一覧を表示したい
実装手順
RecyclerViewを配置LayoutManagerを設定RecyclerView.Adapterを継承したCustomAdapterクラスを実装RecyclerView.ViewHolderを継承したCustomViewHolderクラスを実装CustomViewHolderとCustomAdapterを繋ぎ込みRecyclerViewとCustomAdapterクラスを繋ぎ込み
RecyclerViewを配置
RecyclerViewを画面レイアウトに配置する。ListViewを使ったことがある人はそれと同じ要領。
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
LayoutManagerを設定
LayoutManagerを設定するす。
LayoutManagerはRecyclerViewに対して、コンテンツをどのように配置するかを指定するマネージャークラスで、例えば以下のものがある。
- 縦横にコンテンツを配置する
LinearLayoutManager - グリッドにコンテンツを配置する
GridLayoutManager - キーワードなどを柔軟に並べる
FlexBoxLayoutManager
今回はLinearLayoutManagerを使って、縦並びのコンテンツ配置を指定する。
指定方法は2つ。
コードで設定する方法
コードからLayoutManagerを設定する方法。
LinearLayoutManagerのインスタンスを生成し、RecyclerView.setLayoutManager()で設定する。
val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)
recyclerView.layoutManager = LinearLayoutManager(this)
レイアウトで設定する方法
レイアウトXMLから設定する方法。app:layoutManagerで設定するだけ。
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
RecyclerView.Adapterを継承したCustomAdapterクラスを実装
RecyclerViewで表示する要素を管理するAdapterクラスを実装する。
RecyclerView.Adapterを継承した、CustomAdapterクラスを作成。
class CustomAdapter : RecyclerView.Adapter<ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
TODO("このあと実装")
}
override fun getItemCount(): Int {
TODO("このあと実装")
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
TODO("このあと実装")
}
}
RecyclerView.ViewHolderを継承したCustomViewHolderクラスを実装
RecyclerViewで表示するコンテンツ要素部分を実装する。
RecyclerView.ViewHolderを継承した、CustomViewHolderクラスを作成する。
レイアウトファイルの作成
レイアウトファイルを作成する。ここではファイル名をview_holder_sample.xmlとします。
これは後でCustomViewHolderで指定する。
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/text_view"
android:layout_width="0dp"
android:layout_height="50dp"
android:gravity="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
CustomViewHolderの実装
RecyclerView.ViewHolderを継承したCustomViewHolderクラスを実装する。
サンプルとして、CustomViewHolderに表示用のTextViewへの参照を持たせておく。
class CustomViewHolder(itemView: View): ViewHolder(itemView) {
val textView: TextView = itemView.findViewById(R.id.text_view)
}
CustomAdapterとCustomViewHolderを繋ぎ込み
CustomAdapterとCustomViewHolderを繋ぎ込んでいく。
繋ぎ込み1:onCreateViewでCustomViewHolderを生成
onCreateViewHolderで表示したいCustomViewHolderを生成し、返す。
ここではあくまで生成だけで、実際に表示する要素を当てはめる箇所はonBindViewHolderで実装する。
以下は表示件数を10件とした時の例。
class CustomAdapter : RecyclerView.Adapter<ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
// onCreateViewHolderで、CustomViewHolderを生成する。
return CustomViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.view_holder_sample, parent, false))
}
override fun getItemCount(): Int {
return 10 // 今回はサンプルのため、10件固定で表示する。
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
TODO("このあと実装")
}
}
繋ぎ込み2:onBindViewHolderで表示内容を当て込み
CustomViewHolderのTextViewを参照し、onBindViewHolderで表示内容を当てはめていく。
class CustomAdapter : RecyclerView.Adapter<ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
// onCreateViewHolderで、CustomViewHolderを生成する。
return CustomViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.view_holder_sample, parent, false))
}
override fun getItemCount(): Int {
return 10
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if (holder is CustomViewHolder) {
holder.textView.text = position.toString()
}
}
}
RecyclerViewとCustomAdapterを繋ぎ込み
画面レイアウトに配置したRecyclerViewとCustomAdapterを繋ぎこむ。
val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)
recyclerView.adapter = CustomAdapter()
RecyclerView の表示要素を動的に制御したい
データベースやAPIから取得したデータを一覧に表示する。
実装の手順
CustomAdapterのコンストラクタに表示要素のリストを追加する。getItemCount()メソッドを修正する。onBindViewHolder()で View をカスタマイズする。
1. CustomAdapter のコンストラクタに表示要素のリストを追加する
表示要素を管理するリストを CustomAdapter に渡せるようにする。
今回は、ToDoリストを想定して以下の Todo クラスを用意します。
data class Todo(val id: Int, val title: String)
このデータのリストを CustomAdapter のコンストラクタで受け取る。
class CustomAdapter(private val list: List<Todo>) : RecyclerView.Adapter<ViewHolder>()
2. getItemCount() メソッドを修正する
表示要素の数を設定する。 これは、コンストラクタで受け取ったリストの要素数と同じになります。
override fun getItemCount(): Int {
return list.size
}
3. onBindViewHolder() で View をカスタマイズする
ViewHolder に表示要素を反映する。
onBindViewHolder は表示要素の位置を引数として受け取るため、これを使ってリストの要素にアクセスする。
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if (holder is CustomViewHolder) {
val todo = list[position]
holder.textView.text = todo.title
}
}
クリックしたらその要素に対応する画面を表示したい
実装手順
- タップ時のインターフェースを用意する。
onBindViewHolder()で View がタップされたときの処理を追加する。CustomAdapterのインスタンス生成時にリスナーを設定する。
1. タップ時のインターフェースを用意する
Viewがタップされたときに、Activity や Fragment に必要な情報を渡すためのインターフェースを定義する。
ここでは、クリックされた Todo データを渡す。
interface ToDoClickListener {
fun onClickToDo(todo: Todo)
}
このインターフェースを CustomAdapter のコンストラクタに追加する。
class CustomAdapter(
private val list: List<Todo>,
private val listener: ToDoClickListener
) : RecyclerView.Adapter<ViewHolder>() {
2. onBindViewHolder() で View がタップされたときの処理を追加する
View がタップされたときの処理を実装する。
Todo データへのアクセスが必要になるため、この処理も onBindViewHolder に記述する。
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
if (holder is CustomViewHolder) {
val todo = list[position]
holder.textView.text = todo.title
holder.itemView.setOnClickListener {
listener.onClickToDo(todo) // 要素がタップされたら、それに対応するTodoデータを渡す
}
}
}
3. CustomAdapter のインスタンス生成時にリスナーを設定する
CustomAdapter のインスタンスを生成する際に、先ほど定義したインターフェースの実装を渡す。
以下は、無名オブジェクト生成し渡す例。
val adapter = CustomAdapter(listOf(
Todo(0, "買い物"),
Todo(1, "掃除"),
Todo(2, "洗濯")
), object : ToDoClickListener {
override fun onClickToDo(todo: Todo) {
// ここに画面に反映させる処理や、画面遷移などの必要な処理を実装する
}
})
ドラッグ&ドロップ機能を実装したい
ItemTouchHelperを使う。
実装手順
ItemTouchHelperインスタンスを実装する。ItemTouchHelperをRecyclerViewにアタッチする。
1. ItemTouchHelperインスタンスを実装する
ItemTouchHelperは、ドラッグ&ドロップやスワイプといったユーザーの操作を処理するためのヘルパークラス。
ドラッグ&ドロップ機能を実装するため、SimpleCallbackの特定のメソッドをオーバーライドする。
以下サンプル。
ItemTouchHelper(object : SimpleCallback(UP or DOWN, 0) {
override fun onMove(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
target: RecyclerView.ViewHolder
): Boolean {
// コンテンツがドラッグされようとしている
val fromPosition = viewHolder.adapterPosition
val toPosition = target.adapterPosition
recyclerView.adapter?.notifyItemMoved(fromPosition, toPosition)
// ドラッグしてOKなら true を、NGなら false を返す
return true
}
override fun isLongPressDragEnabled(): Boolean {
// 長押しされた。ドラッグ&ドロップを有効にする
return true
}
override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
// この実装では呼ばれない
}
override fun onMoved(
recyclerView: RecyclerView,
viewHolder: RecyclerView.ViewHolder,
fromPos: Int,
target: RecyclerView.ViewHolder,
toPos: Int,
x: Int,
y: Int
) {
super.onMoved(recyclerView, viewHolder, fromPos, target, toPos, x, y)
// コンテンツが実際にドラッグ&ドロップされた
}
})
補足
isLongPressDragEnabled():ユーザーがアイテムを長押ししたときにドラッグ&ドロップを開始するかどうかの制御。true:有効onMove(): ドラッグ中に呼び出されるドラッグを許可するかどうかの制御。並び替えを許可しないアイテムがある場合あればfalseを返すことでドラックを無効にできる。onMoved(): ドラッグ&ドロップが完了したときに呼び出ばれる。ここでデータリストを更新する。
2. ItemTouchHelperをRecyclerViewにアタッチする
実装したItemTouchHelperをRecyclerViewにアタッチする。
itemTouchHelper.attachToRecyclerView(recyclerView)
参考
最終更新: 2025.9.8