2015年8月30日日曜日

Android RecyclerViewの実装 viewTypeでViewを切り替える

  • 公開日:2015年08月30日

記事概要


AndroidのRecyclerViewでViewを切り替える実装方法を記載した記事です

環境


  • Android Studio 1.3.0
  • OS X Yosemite
  • android sdk 23(Android 6.0 Marshmallow(マシュマロ))
  • com.android.support:recyclerview-v7:23.0.0

はじめに


RecyclerViewを使ったリスト表示の仕方はこの記事を参考にしてください。
また、RecyclerViewを使った下線表示の仕方はこの記事を参考にしてください。
今回は、RecyclerViewでViewを切り替える実装方法を説明します。

RecyclerViewでViewを切り替える


RecyclerViewでリストを表示する場合に、ある一定条件で表示するviewを変更したくなる場合があると思います。

例を挙げると、以下のような画面です。

上記はOpenWeatherMapで取得した予報データをリスト表示しています。
5日分のデータを表示しているのですが、上記の表示方法では日付の区切りがわかりません。
なので、日付が変更になるごとにTextViewで日付を表示するようなラベルのViewを挟む実装をしたいと思います。

Adapterクラスの実装


RecyclerView.AdapterにはviewTypeを習得するメソッドgetItemViewTypeメソッドが用意されています。
このメソッドをオーバーライドします。


    @Override
    public int getItemViewType(int position) {
        WeatherItem weatherItem = mDataSet.get(position);
        if (weatherItem.isLabel) {
            return -1;
        }
        return position;
    }

上記の内容はサンプルです。やっていることは、Adapterで扱うリストの中で、異なるviewを利用するデータのときに、任意のViewTypeの値を返すようにしています。

この戻り値はonCreateViewHolderメソッドで習得することができます。
以下のように実装します。


    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        // Create a new view.
        View v = null;

        if (viewType == -1) {
            v = LayoutInflater.from(viewGroup.getContext())
                    .inflate(R.layout.weather_row_label, viewGroup, false);

        } else {
            v = LayoutInflater.from(viewGroup.getContext())
                    .inflate(R.layout.weather_row_item, viewGroup, false);

        }

        return new ViewHolder(v, viewType);

    }

上記ならviewTypeが-1とその他の値の場合で異なるlayoutのxmlを生成しています。
ViewHolderはRecyclerView.ViewHolderの継承クラスです。ここでは以下のように実装します。


    public static class ViewHolder extends RecyclerView.ViewHolder {
        private TextView timeView;
        private ImageView weatherView;
        private TextView temperatureView;
        private TextView windView;
        private TextView pressureView;

        private TextView timeLabel;

        public ViewHolder(View v, int viewType) {
            super(v);
            // Define click listener for the ViewHolder's View.
            v.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Log.d(TAG, "Element " + getPosition() + " clicked.");
                }
            });

            if (viewType != -1) {
                timeView = (TextView) v.findViewById(R.id.time_value);
                weatherView = (ImageView) v.findViewById(R.id.weather_image);
                temperatureView = (TextView) v.findViewById(R.id.temperature_value);
                windView = (TextView) v.findViewById(R.id.wind_value);
                pressureView = (TextView) v.findViewById(R.id.pressure_value);
            } else {
                timeLabel = (TextView) v.findViewById(R.id.time_label);
            }

        }

        public TextView getTimeView() {
            return timeView;
        }

        public ImageView getWeatherView() {
            return weatherView;
        }

        public TextView getTemperatureView() {
            return temperatureView;
        }

        public TextView getWindView() {
            return windView;
        }

        public TextView getPressureView() {
            return pressureView;
        }

        public TextView getTimeLabel() {
            return timeLabel;
        }


    }

引数で受け取るviewTypeごとに異なるviewのオブジェクトからfieldのオブジェクトを生成しています。
最後にonBindViewHolderメソッドでデータを設定します。


    @Override
    public void onBindViewHolder(ViewHolder viewHolder, final int position) {
        Log.d(TAG, "Element " + position + " set.");

        // Get element from your dataset at this position and replace the contents of the view
        // with that element
        WeatherItem weatherItem = mDataSet.get(position);
        if (viewHolder.getItemViewType() == -1) {
            viewHolder.getTimeLabel().setText(weatherItem.getDisplayDateLabel());
        } else {
            viewHolder.getTimeView().setText(weatherItem.getDisplayTime());
            viewHolder.getWeatherView().setImageResource(R.mipmap.clouds_n);
            viewHolder.getTemperatureView().setText(weatherItem.getDisplayMaxTemperature());
            viewHolder.getWindView().setText(weatherItem.getDisplayWind());
            viewHolder.getPressureView().setText(weatherItem.getDisplayPressure());
        }

    }

viewHolder.getItemViewType()で場合分けしている箇所がポイントです。
では、上記の変更をビルドして画面を立ち上げてみましょう。

日付ごとにラベルが表示されています。

まとめ


RecyclerViewではviewTypeを使うことで自由にViewを切り替えることができます。
RecyclerView.ViewHolderを継承したクラスを複数作ることで、もっと可読性の高いコードにすることも可能だと思います。
viewを4つ5つと多く切り替える必要がある場合は、RecyclerView.ViewHolderを継承したクラスを複数作るほうが後々リファクタリングも楽でしょう。

以上

Androidアプリ開発にオススメの本


開発にあると便利なオススメ製品


関連記事 参考サイト

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

0 件のコメント:

コメントを投稿

Related Posts Plugin for WordPress, Blogger...