KotlinTips: リストの表示(RecyclerView)
概要
Androidでリストを表示するにはListViewとRecyclerViewの二通りのアプローチがありますが、特殊な事情がない限りRecyclerViewを使います。
ListViewは非推奨にはなっていないものの古い設計であり、RecyclerViewの方がより柔軟で最適化された機能を提供しています。
RecyclerViewの使い方を整理してみたいと思います。
サンプル実装はGitHubにあります。
参考資料は主に公式サイトですが下記にまとめてあります。
ViewHolderクラス
ViewHolderはその名前の通りViewを保持するラッパークラスです。
RecyclerViewに規則的に表示されるアイテムを構成するViewをまとめて管理します。
JavaではGetter/Setterを用意せずにpublicなフィールドとしてViewを保持することが多かったかと思います。
また別ファイルとして分けずにAdapterクラスのインナークラスとして記述することが多いと思います。
Adapterクラスのコード量によって別のファイルとするか、同じファイル内に別のクラスとして記述するか、インナークラスとするかなどの方針を決めればよいでしょう。
ここでは明確に整理するためにもあえて別のクラスに分けています。
RecyclerView.ViewHolderクラスを継承し、RecyclerViewに表示するアイテムに合わせて拡張していきます。
ViewHolderクラス自体の機能はViewHolderクラスの中で、ViewHolderクラスの各インスタンスの機能はインスタンス作成時に実装するのがよいかと思います。
class SampleViewHolder(view: View) : RecyclerView.ViewHolder(view) { val title: TextView = view.findViewById(R.id.title) val image: ImageView = view.findViewById(R.id.image) val message: TextView = view.findViewById(R.id.message) val button: Button = view.findViewById(R.id.button) }
Adapterクラス
RecyclerViewが保持するデータとViewHolderクラスを管理し、各データをViewHolderクラスに割り当てます。
この割り当てのことを日本語では「バインド」「バインドする」と言うようです。
RecyclerView.Adapter<ViewHolder>クラスを継承し、実装していきます。
Adapterクラスでは最低でも以下3つのメソッドをOverrideします。
onCreateViewHolder
新しいViewHolderを作成する際にこのメソッドが呼び出されます。
このメソッドでは、LayoutInflaterを取得しxmlファイルからViewHolderを取得し、関連クラスのインスタンスを作成します。
データのバインドはここでは行いませんが、インスタンスの作成やリスナーの作成など、時間のかかる処理がある場合はここで行う方がよいでしょう。
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SampleViewHolder { val layoutInflater = LayoutInflater.from(parent.context) val listItem = layoutInflater.inflate(R.layout.listitem_sample, parent, false) val viewHolder = SampleViewHolder(listItem) viewHolder.run { image.setImageResource(R.mipmap.ic_launcher) button.setOnClickListener { Toast.makeText(button.context, message.text, Toast.LENGTH_SHORT).show() } } return viewHolder }
onBindViewHolder
ViewHolderを表示する準備が必要になった際にこのメソッドが呼び出されます。
このメソッドでは、Adapterが保持するデータリストから該当アイテムの1件分のデータを取得し、ViewHolderにバインドします。
このメソッドはRecyclerViewがスクロールされる際などに頻繁に呼び出されますみ。
負荷がかかる処理を行うとスクロールがスムーズにできなくなりますので、データバインド以外の処理は呼び出さないようにするなど、できるだけ負荷をかけないように注意しましょう。
override fun onBindViewHolder(holder: SampleViewHolder, position: Int) { holder.run { title.text = itemList[position].first message.text = itemList[position].second } }
getItemCount
Adapterが保持するリストデータのサイズを返します。
一般的には単純にサイズを返すだけでよいでしょう。
RecyclerViewはここで取得したサイズ情報を使用して、表示できるアイテムの有無を管理します。
override fun getItemCount(): Int = itemList.size
RecyclerViewの実装
RecyclerViewは基本的にActivityやFragmentでxmlファイルから取得し初期化します。
一般的に必要とされる処理は以下の三つです。
- Adapterクラスの割り当て
- LayoutManagerの設定
- 各アイテムのデコレーション
val recyclerView = findViewById<RecyclerView>(R.id.sample_recycler_view) recyclerView.adapter = SampleRecyclerViewAdapter(listItem) recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false) //区切り線 val itemDecoration = DividerItemDecoration(this, DividerItemDecoration.VERTICAL) recyclerView.addItemDecoration(itemDecoration)
LayoutManagerの設定
RecyclerViewのデータの並びを決定します。
RecyclerViewではリスト形式かグリッド形式、または変則的なグリッド形式の三種類がデフォルトで用意されています。
それぞれLinearLayoutManager、GridLayoutManager、StaggeredGridLayoutManagerの三種類になります。
各アイテムのデコレーション
RecyclerViewでは各アイテムの区切り線などはデフォルトでは設定されていません。
リストの区切り線、グリッドの区切り線などのデコレーションは自分で指定する必要があります。
参考資料
サンプルプログラム
公式サイト
公式サンプルプログラム