ひだまりソケットは壊れない

ソフトウェア開発に関する話を書きます。 最近は主に Android アプリ、Windows アプリ (UWP アプリ)、Java 関係です。

まじめなことを書くつもりでやっています。 適当なことは 「一角獣は夜に啼く」 に書いています。

RecyclerView と view type について (Android アプリ開発)

このエントリでは、ListView の進化版とも言われる *1 RecyclerView の view type について簡単に紹介します。 RecyclerView 自体については次のページを参照してください。

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());

*1:「ListView2」 とか呼ばれてるのをたまに目にします。 実際には ListView の代わりとして以外にも使えます

*2:当然ながら View の構造は別物になるはずですね