前人未踏の領域へ アプリ開発編

Android, iOSアプリ開発に関する調査メモ置き場。はてなダイアリーから移行したため古い記事にはアプリ以外も含まれます。

RecyclerViewにフッターを表示する

課題

RecyclerViewの追加読み込み時にフッターを表示したい。

対策

リストの最後尾にFooter用のオブジェクトを追加し、ViewTypeで判別して出し分け。追加データ取得時に削除する。

エレガントな方法ではないけれど、とりあえず思いつく簡単な方法。

  1. 任意の型を持つFOOTER_VIEWを用意
  2. 追加読み込み時にAdd
  3. RecyclerView.Apadpter内ではViewTypeを判別してフッターに指定したViewTypeの時にFooterViewを返す。
  4. リクエストの戻りがきたらリストからFOOTER_VIEWを削除
//とあるFragmentでの作業を想定
public static final Integer FOOTER_VIEW = new Integer(1);
private List mList;

mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                    //略

                    //リストの末尾に追加
                    LinearLayoutManager manager = (LinearLayoutManager) recyclerView.getLayoutManager();
                    int lastItemPosition = manager.findLastVisibleItemPosition();
                    if (lastItemPosition >= manager.getItemCount() - 1) {
                        Handler handler = new Handler();                         
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                mItems.add(AppConstants.VIEW_TYPE_FOOTER);
                                mAdapter.notifyItemInserted(mItems.indexOf(AppConstants.VIEW_TYPE_FOOTER));
                                requestQuery(); //追加読み込み
                        }
                    });
               }
            }
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                //do nothing
            }
        });

onScrolled内でnotifyItemInsertedを呼ぶと内部で例外が発生するのでHandlerを使ってタイミングを遅らせる。

RecyclerView.Apadpter内でgetItemViewTypeを使い、ViewTypeをうまいことやる。サンプルではinstanceofで見ているが別な方法もあるかと。

//RecyclerView.Apadpterの断片

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View v;
        int storeId = -1;
        RecyclerView.ViewHolder holder = null;
        switch (viewType) {
            case 1:
                v = mInflater.inflate(R.layout.list_item_header, parent, false);
                holder = new HeaderViewHolder(v);
                break;
            case 4:
                v = mInflater.inflate(R.layout.footer_loading, parent, false);
                holder = new FooterViewHolder(v);
                break;
            default:
                v = mInflater.inflate(R.layout.store_search_list_item, parent, false);
                holder = new StoreViewHolder(v);
        }
        return holder;
    }
    /**
     * ViewHolder for Store
     */
    public class FooterViewHolder extends RecyclerView.ViewHolder {
        public FooterViewHolder(View itemView) {
            super(itemView);
        }
    }

    @Override
    public int getItemViewType(int position) {
        Object o = mResults.get(position);
        if (o instanceof String) {
            return 1;
        } else if (o instanceof Integer){
            return 4; //footer or header;
        }
        return 0;
    }

追加のデータがきたらFOOTER_VIEWを削除する。

@Override
public void success(Hoge  hoge, Response response) {
     if ( mStoreList.contains(FOOTER_VIEW) ){
          mStoreList.remove(FOOTER_VIEW);
     }
}

リストのデータの末尾がフッターになる。アイテム件数が一時的に1件増えるので気をつける。