RecyclerView.Adapterは、Item毎にViewTypeを指定することでItem毎にViewHolderを指定出来る。なので「itemが映画ならFilmViewHolderを利用する」とか「itemがドラマならTvDramaViewHolderを利用する」とか「positionが0ならAdViewHolderを利用する」などが出来る。
ただそれをやっていると以下のようにViewHolderのインスタンスを作成するonCreateViewHolder
とViewHolderを利用するonBindViewHolder
がItemViewTypeが増えるたび膨らむ。
public FilmographyAdapter(Context context) {
this.context = context;
}
...
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case VIEW_TYPE_1: {
return new TvDramaViewHolder(LayoutInflater.from(context).inflate(R.layout.row_filmography, parent, false));
}
case VIEW_TYPE_2: {
return new FilmViewHolder(LayoutInflater.from(context).inflate(R.layout.row_filmography, parent, false));
}
default: {
throw new IllegalArgumentException("みつからんかった");
}
}
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
switch (holder.getItemViewType()) {
case VIEW_TYPE_1: {
((TvDramaViewHolder) holder).render(items.get(position));
break;
}
case VIEW_TYPE_2: {
((FilmViewHolder) holder).render(items.get(position));
break;
}
default: {
throw new IllegalArgumentException("みつからんかった");
}
}
}
RecyclerView-Binderというのもあって、それを利用すれば上記のようにswitchで頑張る必要は なさそう。ただViewHolder以外に自分でBinderクラスを作らなければならない事, Adapterに継承が必要なことが理由で利用しなかった。
なので、aptの勉強がてら自分で作ってみた。
github.com
さっきのswitch文べったりなコードがこうなる。
public FilmographyAdapter(Context context) {
this.binder = new FilmographyAdapterViewHolderBinder(context, this);
}
...
void onBindViewHolder(
@ViewHolder(viewType = VIEW_TYPE_1, layout = R.layout.row_filmography) TvDramaViewHolder holder,
int position) {
holder.render(items.get(position));
}
void onBindViewHolder(
@ViewHolder(viewType = VIEW_TYPE_2, layout = R.layout.row_filmography) FilmViewHolder holder,
int position) {
holder.render(items.get(position));
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return binder.create(parent, viewType);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
binder.bind(holder, position);
}
ViewHolderのインスタンスを作成する部分は、僕はいつもこう書いてるだけなので、人間が書く必要はないなと感じた。なので、全部自動生成するようにした。
return new ItemViewHolder(layoutInflater.inflate(R.layout.hogehoge, parent, false));
その結果、ViewTypeが増えれば、 対応したViewHolderとonBindViewHolder(...)
を追加してやるだけになった。
まとめ
- RecyclerViewでViewType毎にViewHolderを分けれるのは便利
- ただ
onCreateViewHolder
などが膨らんでしまい書くコードも多い
- なので、ViewHolderBinderというのを作った
github.com