【Kotlin/Android Studio】RecyclerViewの実装方法!Adapterの役割

この記事からわかること
- Android Studio/KotlinでRecyclerViewを実装する方法
- 必要になる4つのクラス
- AdapterやViewHolder、LayoutManagerの使い方
index
[open]
\ アプリをリリースしました /
参考文献:公式リファレンス:RecyclerView で動的リストを作成する
環境
- Android Studio:Flamingo
- Kotlin:1.8.20
RecyclerViewの使い方
AndroidのRecyclerViewとはアプリで大量のデータをリスト表示する際に使用できるViewGrope
の1つです。RecyclerViewのメリットは個々に表示しているビューをリサイクルすることです。アイテムが画面外にスクロールされてもRecyclerViewはビューを破棄せず新しいアイテムに再利用してくれます。これによりパフォーマンスの大幅な改善とアプリの応答性の向上、消費電力の軽減が期待できます。
またRecyclerViewはJetPackに含まれるライブラリの1つであり、ライブラリ名、クラス名ともにRecyclerViewになっているようです。
RecyclerViewを使用するにあたって重要になるクラス
またRecyclerViewでリストビューを実装するためには以下のクラスが必要になってきます。少しややこしいですがそれぞれの役割をしっかり把握しながら実装していきたいと思います。
- RecyclerView.ViewHolder・・・リスト1行1行のViewを保持するホルダー
- RecyclerView.Adapter・・・Viewに対して操作/描画する(ViewとDataの橋渡し)
- LayoutManager・・・リストレイアウト
- Data Class・・・データ本体
実装の流れ
- Data Classの準備
- RecyclerViewレイアウトの追加
- リストアイテムのレイアウトを構築する
- Adapterの実装
- ViewHolderと紐付け
- ActivityからRecyclerViewにLayoutManagerとAdapterのセット
今回のプロジェクトの全体はGitHubに上げていますので参考にしてください。
Data Classの準備
まずは今回RecyclerViewで表示させたいデータクラスを定義しておきます。以下のようなUser
クラスをdata
ディレクトリを作成してapp/java/com.example.recyclerview/data/
内に定義しておきました。
data class User(
val id: Int,
val name: String,
val age: Int,
val hobby: String
){
companion object {
fun getDemoData(): List<User> {
return listOf(
User(1, "ame", 25, "ボルタリング"),
User(2, "mahiro", 30, "お菓子作り"),
User(3, "sho", 22, "ヒッチハイク"),
User(4, "Joseph", 27, "カフェ巡り"),
User(5, "ito", 42, "小説"),
User(6, "riku", 67, "麻雀"),
User(7, "yoru", 25, "ダイエット"),
User(8, "risa", 31, "映画")
)
}
}
}
またcompanion object
(インスタンス化しないでも参照できる)を使用してデモデータを格納しておきます。
RecyclerViewレイアウトの追加
「activity_main.xml」にRecyclerViewを追加し以下のようにレイアウトを修正しておきます。RecyclerViewにはandroid:layout_width
とandroid:layout_height
を指定しないとOne or more layouts are missing the layout_width or layout_height attributes
というエラーになるので注意してください。
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RecyclerView"
android:textSize="34sp"
app:layout_constraintBottom_toTopOf="@+id/guideline2"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="80dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/main_list"
android:layout_width="match_parent"
android:layout_height="600dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@+id/guideline2" />
この状態では以下のようにitem 0 〜 9
までがプレビューとして表示されます。実際にアプリを起動させてみてもこれらの文字は見えなくなるようです。

リストアイテムのレイアウトを構築する
リスト表示させるにはその1行1行のレイアウトデザインも準備しておく必要があるのでFragmentを作成してXMLで中身を実装していきます。「app」>「java」>「com.example.プロジェクト名」で右クリックして「New」>「Fragment」>「Fragment(Blank)」をクリックしListItemFragment
を作成します。

ListItemFragment
クラスとfragment_list_item.xml
レイアウトが作成されるので先にレイアウトを構築しておきます。
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:padding="10dp">
<TextView
android:id="@+id/user_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="List Item Name"
android:textSize="30sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/user_age"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="30"
android:textSize="14sp"
app:layout_constraintBaseline_toBaselineOf="@+id/age_label"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/age_label" />
<TextView
android:id="@+id/user_hobby"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="5dp"
android:text="サーフィン"
android:textSize="14sp"
app:layout_constraintBaseline_toBaselineOf="@+id/hobby_label"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/hobby_label" />
<TextView
android:id="@+id/age_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="年齢:"
app:layout_constraintStart_toStartOf="@+id/guideline3"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/hobby_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="趣味:"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/age_label" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="231dp" />
</androidx.constraintlayout.widget.ConstraintLayout>

Adapterの実装
AdapterはレンダリングされるView(ViewHolder)と表示させるデータを橋渡しするためのクラスです。そのためAdapterの中にデータを保持するためのプロパティとViewHolderクラスを定義していきます。AdapterクラスはRecyclerView.Adapter
をViewHolderクラスはRecyclerView.ViewHolder
を継承して定義しておきます。これで必要なメソッドを定義することができるようになります。
import android.view.View
import androidx.recyclerview.widget.RecyclerView
class MainAdapter :RecyclerView.Adapter<MainAdapter.MainViewHolder>() {
class MainViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
}
}
まずはデータを保持するためのデータリストを用意します。クラス内でのみ操作をするのでprivate
で、変更できるようにMutableList
で宣言しています。またMainAdapter
クラスをインスタンス化する際に引数でList
を受け取れるように変更しておきます。
class MainAdapter(userList: List<User>) :RecyclerView.Adapter<MainAdapter.MainViewHolder>() {
private val _userList: MutableList<User> = userList.toMutableList()
override fun getItemCount(): Int = _userList.size
// 〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜〜
getItemCount
メソッドは実装が必須になるので定義しておきます。ここにはデータの数を格納します。
ViewHolderと紐付け
続いてViewHolderと紐付けしていきます。ここでやっていることの詳細はコメントに残しておきました。ざっくりやっていることは以下のとおりです。
・ViewHolderを配置するレイアウト(fragment_item_list.xml)の指定
・レイアウト(fragment_item_list.xml)の要素をViewHolderに紐付け
・ViewHolderにバインドするデータのセット
// 新しいViewHolderオブジェクトを作成し、RecyclerViewに表示するアイテムのレイアウトを指定
// parent:新しいViewHolderが配置される親ViewGroup受け取る
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainViewHolder {
return MainViewHolder(
// XMLレイアウトファイルからViewオブジェクトを作成
LayoutInflater.from(parent.context).inflate(R.layout.fragment_list_item, parent, false)
)
}
// データをViewHolderにバインドするメソッド
// positionからバインドするビューの番号が受け取れる
// その番号のデータをリストから取得しholderにセット
override fun onBindViewHolder(holder: MainViewHolder, position: Int) {
val user = _userList[position]
holder.name.text = user.name
holder.age.text = user.age.toString()
holder.hobby.text = user.hobby
}
// itemView:アイテムレイアウトファイルに対応するViewオブジェクト
// 「fragment_item_list」の要素を取得しHolderを構築
class MainViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val name: TextView = itemView.findViewById(R.id.user_name)
val age: TextView = itemView.findViewById(R.id.user_age)
val hobby: TextView = itemView.findViewById(R.id.user_hobby)
}
ActivityからRecyclerViewにLayoutManagerとAdapterのセット
最後にActivityからRecyclerView
にLayoutManagerとAdapterのセットします。LinearLayoutManager
は既存でクラスが用意されているので特に準備する必要はありませんでした。
val recyclerView: RecyclerView = findViewById(R.id.main_list)
recyclerView.layoutManager = LinearLayoutManager(this)
recyclerView.addItemDecoration(
DividerItemDecoration(this, DividerItemDecoration.VERTICAL)
)
recyclerView.adapter = MainAdapter(User.getDemoData())

これでRecyclerViewを使用してリストビューを実装することができました。
おすすめ記事
【Kotlin/Android Studio】ItemTouchHelperの使い方!RecyclerViewでスワイプ処理を実装する方法
【Kotlin/Android Studio】SimpleOnItemTouchListenerの使い方!RecyclerViewでタップイベントを実装する方法
グリッドレイアウトを実装する
RecyclerViewでは以下のようなグリッドレイアウトも簡単に実装することが可能です。詳細は以下の記事を参考にしてください。

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。
ご覧いただきありがとうございました。