RecyclerViewで行ごとに表示を切り替える
Recycler View
で行ごとに表示に使うレイアウトを切り替える、というのをやりたくて悪戦苦闘していましたので、とりあえず書いたのをメモ。
参考にしたのは、
Tumbling Dice — [Android]ListViewのレイアウトを動的に切り替える際の問題点
全体として出来上がったコードはここ。
内容
- RecyclerViewを利用する側の準備
- ViewHolderで使うレイアウトの準備
- ViewHolderの準備
- 切り替えたいレイアウトに対応するViewHolderのサブクラスを用意する
- onCreateViewHolder()でViewHolderのサブクラスを返すようにする
- getItemViewType()でdataの値に応じた値を返すようにする
- onBindViewHolder()でサブクラスのメソッドを使う
- 実際に動かした画面
RecyclerViewを利用する側の準備
RecyclerView
を利用する側の準備。
まず、利用したいActivity
にRecyclerView
の要素を入れる。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"> <android.support.v7.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/recycler_view" android:layout_width="match_parent" android:layout_height="match_parent" app:layoutManager="android.support.v7.widget.LinearLayoutManager" /> </RelativeLayout>
Activity
から、RecyclerView
のインスタンスを取得。
Adapter
にセットするList<T>
の取得を行い、LayoutManager
とAdapter
をセット。
RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view); LinearLayoutManager layoutManager = new LinearLayoutManager(this); recyclerView.setLayoutManager(layoutManager); List<SampleItem> data = new ArrayList<>(); // 中略 // SampleItemというオブジェクトのcategoryという値によって // レイアウトを切り替えるので、catagoryの異なる // オブジェクトを30個くらい生成 recyclerView.setAdapter(new SampleAdapter(this, data));
ViewHolderで使うレイアウトの準備
とりあえず、各行で切り替えて使おうと思っているレイアウトリソースを下記のような形のものを3つ用意。
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="3dp" android:background="#FF0000" <!-- 2 -> #00FF00 3 -> #0000FF --> android:text="New Text" android:id="@+id/textView1" /> <!-- textViewn --> </LinearLayout>
切り替えたいレイアウトに対応するViewHolderのサブクラスを用意する
こういった上のレイアウトファイルに対応したリソースへの参照等を持つ ViewHolder
のクラスを作成する。
これらのサブクラスに、切り替えたレイアウトのIDやレイアウト中へのリソースへのを参照を持たせて、Bindの際もこのクラスのメソッドを使わせる。
public class Sample1ItemViewHolder extends ViewHolder { public static final int LAYOUT_ID = R.layout.sample_1_item_view; public final TextView textView; public Sample1ItemViewHolder(View itemView) { super(itemView); textView = (TextView) itemView.findViewById(R.id.textView1); } public void onBindItemViewHolder(SampleItem data) { this.textView.setText(data.getText()); } }
もしかしたら、レイアウトのインスタンスも持っていていいかもしれない。
ViewHolder
のサブクラスなのがポイント。
onCreateViewHolder()でViewHolderのサブクラスを返すようにする
@Override public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case 1: return new Sample1ItemViewHolder(inflater.inflate(Sample1ItemViewHolder.LAYOUT_ID, parent, false)); case 2: return new Sample2ItemViewHolder(inflater.inflate(Sample2ItemViewHolder.LAYOUT_ID, parent, false)); case 3: return new Sample3ItemViewHolder(inflater.inflate(Sample3ItemViewHolder.LAYOUT_ID, parent, false)); } return null; }
getItemViewType()でdataの値に応じた値を返すようにする
どちらかというと、特定の値がBlankのとき、切り替える、とかいう場合もあるかもしれない。
public int getItemViewType(int position) { return data.get(position).getCategory(); }
onBindViewHolder()でサブクラスのメソッドを使う
こうしておくと、切り替えたいレイアウトを増やしたとき、そのレイアウトに関するデータのbindingはサブクラスだけを見ていれば良いので比較的すっきりする気がします。
@Override public void onBindViewHolder(ViewHolder holder, int position) { switch (getItemViewType(position)) { case 1: ((Sample1ItemViewHolder)holder).onBindItemViewHolder(data.get(position)); break; case 2: ((Sample2ItemViewHolder)holder).onBindItemViewHolder(data.get(position)); break; case 3: ((Sample3ItemViewHolder)holder).onBindItemViewHolder(data.get(position)); break; } }
実際に動かした画面
こうです。