GridViewからRecyclerViewに移行したい
2015/07/05
GridViewからRecyclerViewにクラス名変えるだけじゃ動かない。
移行過程をメモ。
Contents
dependencyにrecyclerviewを追加する
まずsupport libraryを導入する。
1 |
compile 'com.android.support:recyclerview-v7:22.2.0' |
Adapterがaddできない
RecyclerViewではRecyclerView.Adapter
なので、既存のAdapterクラスだとダメ。
clearができない
ArrayListAdapterクラスとかではclearメソッドが用意されていたがRecyclerView.Adapterではclearが無い。
なので自分で実装する必要がある。
1 2 3 4 |
public void clear() { itemList.clear(); notifyDataSetChanged(); } |
DataSourceに対する操作(add,addAll,clearなどなど。。)を誰が担うべきなのかよく分かってないので、上記の書き方が合ってるか謎ではある。
addAllができない
同上。
1 2 3 4 |
public void addAll(ArrayList<Item> itemList) { this.itemList.addAll(itemList); notifyDataSetChanged(); } |
setSelectionが使えなくなった
スクロール位置を保存しておいて、リスト画面→詳細画面→リスト画面と詳細画面から戻ってきたときにスクロール位置を復元するために使ったりしてる。
で、このスクロール位置を指定する役割はLayoutManagerクラスが担うことになったみたい。
GridLayoutManagerやLinearLayoutManagerを見てみる。
- scrollToPositionWithOffset(int position, int offset)
- scrollToPosition(int position)
1 2 |
gridView.setLayoutManager(layoutManager); layoutManager.scrollToPosition(position); |
このあたりを使えばOK。
setEmptyViewが使えなくなった
TODO : 書く
getFirstVisiblePositionが使えなくなった
前述のLayoutManagerクラスが担ってる。
1 |
int position = layoutManager.findFirstVisibleItemPosition(); |
各Grid間のマージンが指定できない
GridViewではxmlでverticalSpacing=”8dp”とか指定すれば良かった。
RecyclerViewではマージン追加処理を載せたItemDecorationをAdapterにsetすることで実現できる。
An ItemDecoration allows the application to add a special drawing and layout offset to specific item views from the adapter’s data set. This can be useful for drawing dividers between items, highlights, visual grouping boundaries and more.
と、ドキュメントに書いてるようにonCreateViewHolderで生成したViewを土台にして、追加で何かを描画するとか、マージンを追加したいといった処理を担うのがItemDecorationクラス。
下記を読めばOK。
http://stackoverflow.com/a/28533234/2451025
上の記事ではviewのポジションに応じてマージンの有無を調節している。
viewのタイプに応じて処理を切り替える、なんてこともできる。
1 2 3 4 5 6 7 8 |
@Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { if (parent.getChildViewHolder(view).getItemViewType() == AWESOME_HEADER) return; outRect.left = space; outRect.right = space; outRect.bottom = space; outRect.top = space; } |
AWESOME_HEADER(int)タイプのviewだったら何もせず、それ以外のタイプのViewにはマージンを設定する。というものだ。
タイプが増えてくるとif文かswitch文だらけになるので、複雑度に応じて適宜Enumなどを使って処理を分岐させるなど、清潔な感じにしておくとよさ気。
Header追加したい
GridViewにはHeaderやFooterを追加する機能が無い。
なので、偉い人たちが作ってくれている。
https://github.com/liaohuqiu/android-GridViewWithHeaderAndFooterとかhttps://github.com/recruit-mp/android-HeaderFooterGridViewとかある。
一方、RecyclerViewではSpanSizeLookupクラスを使うことでHeaderやFooterらしいモノを作れるようになった。
例えば。。
1 2 3 4 5 6 7 |
layoutManager = new GridLayoutManager(getActivity(), 3); layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { return adapter.isHeader(position) ? layoutManager.getSpanCount() : 1; } }); |
こんな感じ。
1 |
layoutManager = new GridLayoutManager(getActivity(), 3); |
これで3列のGridが使えるようになった。
Gridの要素は3分割された小さいViewでOKだが、Headerだけは横幅いっぱいのwidthが欲しい。
こういうときにSpanSizeLookup()を使う。
1 2 3 4 5 6 |
layoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() { @Override public int getSpanSize(int position) { return isHeader(position) ? layoutManager.getSpanCount() : 1; } }); |
getSpanSizeメソッドで「あるポジションのViewは分割された要素何個分の大きさにすべきか?」を指定できる。
isHeaderメソッドは独自に実装したヤツなので、がんばって書く。
isHeaderがtrueであれば『layoutManager.getSpanCount() = 3』となる。Grid3個分のサイズだ。
falseであれば1なので、Grid1個分のサイズ。
これは便利。
336px
336px
関連記事
- PREV
- Docker Machineのメモ
- NEXT
- [WIP]普通の服について考えてみた