リサイクラービューを使ってリスト表示【Android・Kotlin】

今回のAndroidサンプルプロジェクトでは、リサイクラービューを使って図の正方形のリストアイテムの表示を行ってみた。


画像の拡大

この記事ではリサイクラービューの実装手順を説明していく。

リサイクラービューとは

リサイクラービューとは、リストビューよりも柔軟性の高い表現ができるビューである。リスト内にカードやカルーセルを並べたり、横方向にスクロールさせたり、リストアイテムをグリッド状に並べたりすることができる。

リサイクラービューのレイアウトマネージャーには次の3つが用意されている。

  1. LinearLayoutManager
  2. GridLayoutManager
  3. StaggeredGridLayoutManager

LinearLayoutManagerはリストビューと似ていて、アイテムを縦に並べる事ができるが横にも並べることができるものだ。GridLayoutManagerはグリッド状にリストアイテムを並べることができる。今回のサンプルプログラムではこのGridLayoutMnagerを使ったリサイクラービューを実装する。最後のStaggeredGridLayoutManagerGridLayoutManagerをさらに柔軟にしたものと言えよう。Staggeredとは「ジグザグの」と言う意味で、GridLayoutManagerでは普通、行の高さが揃うことになっているがこのレイアウトでは行の高さを別々にすることができるのだ。

これからリサイクラービューを使う上で注意しておきたいのは、リサイクラービューはサポートライブラリーに含まれることだ。サポートライブラリとは古いOSでも使用できるように後方互換を考慮したライブラリだ。リサイクラービューはバージョン7に含まれるのでGradleでは次のように追加されることになる。

implementation 'com.android.support:recyclerview-v7:28.0.0'

Adapterクラスの作成

それではリサイクラービューを作っていこう。

リストビューの時と違ってBaseAdapterではなくRecyclerViewに定義されているAdapterクラスを継承して実装する。

またリストビューと同様にViewHolderパターンを使用する。

class SampleAdapter(context: Context, private val onItemClicked: (TimeZone) -> Unit):
        RecyclerView.Adapter<SampleAdapter.SampleViewHolder>() {

    private val inflater = LayoutInflater.from(context)
    private val timeZones = TimeZone.getAvailableIDs().map {
        id -> TimeZone.getTimeZone(id)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SampleViewHolder {
        val view = inflater.inflate(R.layout.list_time_zone_row, parent, false)
        val viewHolder = SampleViewHolder(view)

        view.setOnClickListener {
            val position = viewHolder.adapterPosition
            val timeZone = timeZones[position]
            onItemClicked(timeZone)
        }
        return viewHolder
    }

    override fun getItemCount(): Int = timeZones.size

    override fun onBindViewHolder(holder: SampleViewHolder, position: Int) {
        val timeZone = timeZones[position]
        holder.timeZone.text = timeZone.id
    }


    class SampleViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        val timeZone = view.findViewById<TextView>(R.id.timeZone)
    }

}

リサイクラービューで実装すべきメソッドは次の3つである。

  1. getItemCount():Int
  2. onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder
  3. onBindViewHolder(holder: SampleViewHolder, position: Int)

それではこれらを順番に見ていこう。

getItemCount():Int

ここではリストアイテムの件数を返すことになっている。リストビューの時とは異なり、ヘッダーやフッターもカウントの対象となることに注意しよう。今回はヘッダーもフッターも表示しないのでTimeZoneで得られた配列のサイズをそのまま返すことになっている。

onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder

ここでは表示するリストアイテムのViewをinflaterで生成する。ViewHolderパターンを使うので、RecyclerView.ViewHolderを継承したSampleViewHolderクラスを作りそれを返すことにした。またリストアイテムをクリックしたときのイベントハンドラの登録もここで行うようにしよう。

onBindViewHolder(holder: ViewHolder, position: Int)

ここではonCreateViewHolderで生成したViewHolderが渡されるので、表示させたい値をここで設定しよう。

MainActivityでRecyclerViewの設定

RecyclerViewのプログラムができたところで、MainActivityからRecyclerViewを呼び出す設定をしよう。

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        
        val sampleAdapter = SampleAdapter(this) { timeZone ->
            Toast.makeText(this, timeZone.displayName, Toast.LENGTH_SHORT).show()
        }
        val gridManager = GridLayoutManager(this, 4)

        val recyclerView = findViewById<RecyclerView>(R.id.timeZoneList). apply {
            adapter = sampleAdapter
            layoutManager = gridManager
        }

    }
}

今回はSampleAdapterクラスのコンストラクタの第二引数に、ラムダ式を渡す仕様となっている。ラムダ式内にリストアイテムがクリックされたときの処理を書き込もう。

GridLayoutManagerの第二引数には1行に配置したいリストアイテムの数を指定することができる。

以上のプログラムをBuild&Runすると、リサイクルビューを表示することができた。



画像の拡大

正方形のマスを画面サイズに合わせてキレイに配置する

ところで、正方形のリストアイテムをグリッドで並べたい場合、どうすればよいだろうか?

まず、list_time_zone_row.xmlTextViewのサイズを次のように固定にしてしまおう。

android:layout_width="80dp"
android:layout_height="80dp"

しかし画面が回転したりして横幅が大きくなってしまうと、ムダにスペースが空いてしまう。そこで画面の現在の横幅(dp)を取得して何個リストアイテムを入れられるか計算させる。onCreateメソッド内を次のように修正した。

val screenWidthDp = resources.configuration.screenWidthDp // 追記
val spanCount:Int = screenWidthDp / 88 // 追記
val gridManager = GridLayoutManager(this, spanCount) // spanCountに修正

すると次のように画面サイズに合わせてキレイに配置することができた。


画像の拡大

以上でリサイクラービューの基本的な使い方の説明を終わる。

今回のサンプルはGitHubへ公開しておく。

公式ドキュメント

▼ こんな記事も書いてます。

記事に関するご質問などがあれば、
@tosisico または お問い合わせ までご連絡ください。
関連記事