前回の続き。今回は行ごとに異なるViewを表示するための解説です。

サンプルコード: https://github.com/stack3/AndroidListViewSamples

サンプルを起動してMultipleTypeを選択してください。以下の様な画面が表示されます。

01

前回のTitleとDescriptionを縦に並べて表示と、LeftとRightに横に並べて表示する行が混在しています。

CustomListItem2

前回のCustomListItemはTitleとDescriptionを保持しました。今回のCustomListItem2はLeftとRightを行データとして保持するようにします。

public class CustomListItem2 {
    private String leftText;
    private String rightText;

    public String getLeftText() {
        return leftText;
    }

    public void setLeftText(String leftText) {
        this.leftText = leftText;
    }

    public String getRightText() {
        return rightText;
    }

    public void setRightText(String rightText) {
        this.rightText = rightText;
    }
}

※ 文字列2つを保持するならCustomListItemのままでいいんじゃないのという突っ込みはご容赦を・・・あくまでサンプルなので異なるタイプの扱い方が要点ですので。

MultipleTypeAdapter

今回のAdapterはCustomListItem/CustomListItemという異なるクラスをList管理するためにList<Object>で宣言しています。

private List<Object> items;

getCount、getItem、getItemIdは前回同様なので割愛。

異なる行タイプを扱う上で大事なのは、getViewTypeCountとgetItemViewTypeのオーバーライドです。

getViewTypeCountは、行のタイプ数を返します。つまり今回は2タイプなので2を返せばよいわけです。

@Override
public int getViewTypeCount() {
    return 2;
}

getItemViewTypeの方は、引数positionの行のタイプごとに一意のインデックス値を返します。今回は2タイプなので、タイプごとに0か1かを返します。

@Override
public int getItemViewType(int position) {
    Object item = items.get(position);
    if (item instanceof CustomListItem) {
        return 0;
    } else {
        return 1;
    }
}

わかりやすくするためにgetViewTypeCountとgetItemViewTypeの実装をこのようにしましたが、実際のサンプルはより多くのタイプを扱うことを前提に以下のようにしています。

行タイプを格納するListをメンバー変数として宣言

private List&lt:Object> viewTypes;

コンストラクタで初期化。ListにCustomListItem/CustomListItem2のクラスを入れる。

this.viewTypes = new ArrayList&lt:Object>();
this.viewTypes.add(CustomListItem.class);
this.viewTypes.add(CustomListItem2.class);

getItemViewTypeで、itemsからpositionの行データを取り出して、そのクラスからviewTypesメンバー変数を使ってインデックスを得て返す。

@Override
public int getItemViewType(int position) {
    Object item = items.get(position);
    return viewTypes.indexOf(item.getClass());
}

このようにしておくと、行のタイプが増えても対応しやすいと思います。

最後にgetViewの実装。

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    View customItemView = null; 

    Object baseItem = items.get(position);
    if (baseItem instanceof CustomListItem) {
        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            customItemView = inflater.inflate(R.layout.custom_list_item, parent, false);
            Log.d(this.getClass().getName(), "custom 1 created");
        } else {
            customItemView = convertView;
            Log.d(this.getClass().getName(), "custom 1 recycled");
        }

        CustomListItem item = (CustomListItem)baseItem;
        TextView titleTextView = (TextView)customItemView.findViewById(R.id.titleTextView);
        TextView descriptionTextView = (TextView)customItemView.findViewById(R.id.descriptionTextView);
        titleTextView.setText(item.getTitle());
        descriptionTextView.setText(item.getDescription());
    } else { // CustomListItem2
        if (convertView == null) {
            LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
             customItemView = inflater.inflate(R.layout.custom_list_item_2, parent, false);
             Log.d(this.getClass().getName(), "custom 2 created");
         } else {
             customItemView = convertView;
             Log.d(this.getClass().getName(), "custom 2 recycled");
         }

         CustomListItem2 item = (CustomListItem2)baseItem;
         TextView leftTextView = (TextView)customItemView.findViewById(R.id.leftTextView);
         TextView rightTextView = (TextView)customItemView.findViewById(R.id.rightTextView);
         leftTextView.setText(item.getLeftText());
         rightTextView.setText(item.getRightText());
     }

     return customItemView;
}

ちょっと長いですが、やっていることは以下のとおりです。

  • positionの行データを得る
  • instanceofで行データのタイプを判断
  • CustomListItemならcustom_list_item、CustomListItem2ならcustom_list_item_2をレイアウトとしたViewを生成する。もちろんViewを使いまわせるときはする
  • それぞれのViewからChildView(TextView)を得て行データを設定する

その6へ続く