Tatsuro のテックブログ

アプリ開発の技術情報を発信します。

【Android × Kotlin】RecyclerView でリスト表示する

今回は、RecyclerView でリスト表示する方法を解説します。

なお、ここに掲載しているソースコードは以下の環境で動作確認しています。

  • Android Studio Bumblebee | 2021.1.1 Patch 3
  • JDK 11.0.11
  • Android Gradle Plugin 7.1.3
  • Kotlin 1.6.21
  • Gradle 7.4.2
  • androidx.recyclerview 1.2.1

RecyclerView でリスト表示する

RecyclerView とは、大きなデータセットを並べて表示できる ViewGroup です。並べ方を設定することができ、リストやグリッドなどで表示することができます。

今回は、以下のようなリストを表示してみます。

ライブラリのインポート

RecyclerView を使えるようにするために、アプリの build.gradle ファイルに次の依存関係を追加します。

dependencies {
    implementation "androidx.recyclerview:recyclerview:1.2.1"
}

データクラスの作成

まず、RecyclerView に表示するデータクラスを作成します。今回は、リストの各項目ごとに 2 つの文字列を表示するので、データクラスにも String 型文字列を 2 つ用意します。

data class TwoLines(
    val primary: String = "Primary text",
    val secondary: String = "Secondary text",
)

レイアウトファイルの作成

次に、レイアウトファイルを作成します。RecyclerView を使用する場合、RecyclerView を構成する各項目のレイアウトファイルを作成する必要があります。

<?xml version="1.0" encoding="utf-8"?>
<!-- two_lines_item.xml -->
<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"
    android:layout_margin="4dp">

    <ImageView
        android:id="@+id/iconImage"
        android:layout_width="60dp"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_baseline_android_24"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <TextView
        android:id="@+id/primaryText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:textColor="@color/black"
        android:textSize="18sp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/iconImage"
        app:layout_constraintTop_toTopOf="parent"
        tools:text="Primary text" />

    <TextView
        android:id="@+id/secondaryText"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@id/iconImage"
        app:layout_constraintTop_toBottomOf="@id/primaryText"
        tools:text="Secondary text" />

</androidx.constraintlayout.widget.ConstraintLayout>

なお、Activity については、RecyclerView のインスタンスを直接 AppCompatActivity#setContentView に渡すため、Activity のレイアウトファイルを作成しません。

アダプタの作成

そして、RecyclerView のアダプタを作成します。RecyclerView のアダプタは、RecyclerView とそれに表示するデータセットを紐付ける役割を持ちます。

class TwoLinesListAdapter(
    private val twoLinesList: List<TwoLines>
) : RecyclerView.Adapter<TwoLinesListAdapter.ViewHolder>() {

    inner class ViewHolder(view: View) :
        RecyclerView.ViewHolder(view) {

        val primaryText: TextView =
            view.findViewById(R.id.primaryText)
        val secondaryText: TextView =
            view.findViewById(R.id.secondaryText)
    }

    override fun onCreateViewHolder(
        parent: ViewGroup, viewType: Int
    ): ViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.two_lines_item, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(
        holder: ViewHolder, position: Int
    ) {
        holder.apply {
            val twoLines = twoLinesList[position]
            primaryText.text = twoLines.primary
            secondaryText.text = twoLines.secondary
        }
    }

    override fun getItemCount() = twoLinesList.size
}

RecyclerView のアダプタには、以下を実装する必要があります。

  • RecyclerView.Adapter の継承
class TwoLinesListAdapter(
    private val twoLinesList: List<TwoLines>
) : RecyclerView.Adapter<TwoLinesListAdapter.ViewHolder>() {
    ︙
  • ViewHolder の定義

ViewHolder には、RecyclerView に表示する各項目の View を持たせます。RecyclerView は自身がスクロールされるたびに、既存の ViewHolder インスタンスに新しいデータを設定することで、ViewHolder インスタンスを使い回し、効率よく動作します。

    inner class ViewHolder(view: View) :
        RecyclerView.ViewHolder(view) {

        val primaryText: TextView =
            view.findViewById(R.id.primaryText)
        val secondaryText: TextView =
            view.findViewById(R.id.secondaryText)
    }
  • RecyclerView.Adapter#onCreateViewHolder のオーバーライド

ここでは、さきほど作成した ViewHolder インスタンスの生成処理を実装する必要があります。

    override fun onCreateViewHolder(
        parent: ViewGroup, viewType: Int
    ): ViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.two_lines_item, parent, false)
        return ViewHolder(view)
    }
  • RecyclerView.Adapter#onBindViewHolder のオーバーライド

ここでは、引数に渡された ViewHolder インスタンスに新しいデータを設定する処理を実装する必要があります。

    override fun onBindViewHolder(
        holder: ViewHolder, position: Int
    ) {
        holder.apply {
            val twoLines = twoLinesList[position]
            primaryText.text = twoLines.primary
            secondaryText.text = twoLines.secondary
        }
    }
  • RecyclerView.Adapter#getItemCount のオーバーライド

このメソッドは、RecyclerView に表示するデータセットのサイズを返す必要があります。

    override fun getItemCount() = twoLinesList.size

RecyclerView の設定

最後に、RecyclerView に対して必要な設定を行います。

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        RecyclerView(this).also {
            it.layoutParams = ViewGroup
                .LayoutParams(MATCH_PARENT, MATCH_PARENT)
            setContentView(it)

            // リスト表示
            val layoutManager =
                LinearLayoutManager(this@MainActivity)
            it.layoutManager = layoutManager

            // 罫線の追加
            val dividerItemDecoration = DividerItemDecoration(
                this@MainActivity, layoutManager.orientation
            )
            it.addItemDecoration(dividerItemDecoration)

            // データの追加
            val data: List<TwoLines> = List(20) { TwoLines() }
            it.adapter = TwoLinesListAdapter(data)
        }
    }
}

今回は、RecyclerView に対して以下の設定を行います。

  • LayoutManager の設定

データセットの並べ方を設定します。今回はリスト表示なので、LinearLayoutManager を設定します。

            // リスト表示
            val layoutManager =
                LinearLayoutManager(this@MainActivity)
            it.layoutManager = layoutManager
  • ItemDecoration の追加

RecyclerView は、デフォルトの設定では罫線を表示しません。罫線を表示させるために、DividerItemDecoration を追加します。

            // 罫線の追加
            val dividerItemDecoration = DividerItemDecoration(
                this@MainActivity, layoutManager.orientation
            )
            it.addItemDecoration(dividerItemDecoration)
  • アダプタの設定

さきほど作成したアダプタにデータセットを設定し、そのアダプタを設定します。

            // データの追加
            val data: List<TwoLines> = List(20) { TwoLines() }
            it.adapter = TwoLinesListAdapter(data)

参考

RecyclerView で動的リストを作成する

関連記事

RecyclerView に View Binding を導入する方法について、以下で解説しています。

tatsurotech.hatenablog.com