RecyclerView と view type について (Android アプリ開発)
このエントリでは、ListView
の進化版とも言われる *1 RecyclerView
の view type について簡単に紹介します。 RecyclerView
自体については次のページを参照してください。
- Creating Lists and Cards | Android Developers (公式のトレーニングガイド)
- Material Designの目指すところとAndroid側の変更点 - クックパッド開発者ブログ (Cookpad の技術ブログでの簡単な紹介)
- [Android] RecyclerView を使ってみました - adakoda (使い方の面での
ListView
との比較がわかりやすい)
View type とは
View type が何であるかの公式的な説明は見当たらなかったのですが、要は 1 つの RecyclerView
の要素として複数種類の View
を使い分けるための仕組みです。
例えば、RecyclerView
の中でコンテンツと見出しの表示要素 *2 を混在させたい場合、コンテンツと見出しを別の view type として扱うことで出し分けが容易になります。
他にも、リストの最後の項目として 「続きを読む」 というような項目を表示したい場合も通常の view type とは別の view type の項目として扱えば良いですね。
各項目の view type の指定方法
各項目の view type を指定するには、RecyclerView.Adapter#getItemViewType(int)
メソッドをサブクラスでオーバーライドします。 デフォルト実装は常に 0
を返すというものですので、RecyclerView
の中で単一種類の表示項目しか扱わない場合はオーバーライドする必要はありません。
View type の値は int
型です。 ドキュメントには、衝突することを避けるために id リソースを使うことを検討するように、と書かれています。
View type ごとの View の生成
RecyclerView.Adapter#onCreateViewHolder(ViewGroup, int)
メソッド の第 2 引数として view type の値が渡されてきます。 なので、このメソッドの中で生成する view を view type ごとに変化させ、ViewHolder
にセットすることになります。
ViewHolder
が保持している view の view type を知る方法
RecyclerView.ViewHolder#getItemViewType()
メソッド が、ViewHolder
が保持している view の view type を返してくれます。 なので、RecyclerView.Adapter#onBindViewHolder(VH, int)
メソッドの中などで view type を知りたいときはこのメソッドを使いましょう。
サンプルコード
複数 view type を使う Adapter
のサンプルコードです。 (とりあえず動くという程度の簡単な実装です。)
package info.vividcode.android.example; import android.support.v7.widget.RecyclerView; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> { public static class ViewHolder extends RecyclerView.ViewHolder { public ViewHolder(View itemView) { super(itemView); } } @Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { // view type に応じて生成する view を変える。 // 今回はサンプルコードなので手軽に両方とも TextView にしている。 // 実際にはここで生成する View を違うものにする。 View v; if (viewType == 0) { v = new TextView(parent.getContext()); } else { v = new TextView(parent.getContext()); } return new ViewHolder(v); } @Override public void onBindViewHolder(ViewHolder holder, int position) { // view type に応じて処理を分ける。 // 今回はどちらも TextView なので単にセットする文字列を変えている。 if (holder.getItemViewType() == 0) { ((TextView) holder.itemView).setText("Even: " + position); } else { ((TextView) holder.itemView).setText("Odd: " + position); } } @Override public int getItemViewType(int position) { // サンプルコードなので手軽に position が偶数の項目と奇数の項目で view type を分ける。 return position % 2; } @Override public int getItemCount() { return 10; } }
これを Activity
のメソッド内で以下のようにして使えばとりあえず動きます。
// recyclerView はどこかで既に定義されているとする。 LayoutManager layoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager); recyclerView.setAdapter(new MyRecyclerViewAdapter());