いろいろガンガンいこうぜ。体も大事に

普段はJavaでAndroidアプリ開発しているプログラマーのブログです。

ListAdapterについて調べてみた(1) ArrayAdapter編

ArrayAdapterを継承して,getViewをオーバーライドしたり,Adapter内でViewHolderをインナークラスで定義したり,セルのビューのタグにホルダーをセットしたりなどは今回しません。ArrayAdapterを継承せずに,そして非常に少ないコード記述量で使ってみます。


ArrayAdapterクラスのコンストラクタは,TextView単体のレイアウトXMLファイルのidを引数にとったり,レイアウトXMLファイルのidとその中のTextViewのidを引数に取ったりするものがあります。リスト内のセルの構成要素がTextViewだけ,もしくは単一のTextViewの表示内容だけがセルごとに異なる場合,非常に少ないコード記述量でリストを表示できるようです。(もちろんArrayAdapterは,getViewメソッドをオーバーライドすることで,画像や複数のTextViewが一つのセル内にあるようなリストを作ることも可能です。)


シンプルな使い方

(多分一度は見たことがある)ArrayAdapterの基本的な使い方。
下記のようなTextViewのみで構成されているレイアウトXMLファイルを用意します。

res/layout/list_item_text_view.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/label"
    android:layout_width="match_parent"
    android:layout_height="40dp"
    android:gravity="center"
    android:text="Label" >

</TextView>


このレイアウトXMLファイルのidと,文字列の配列からArrayAdapterのインスタンスを作ります。(ActivityのonCreate内。thisはActivityのインスタンス)

String[] strings = new String[] {
	"日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"
};

int itemLayoutId = R.layout.list_item_text_view;
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, itemLayoutId, strings);

このAdapterを用いてテキストのみの簡単なリストを表示することが可能です。
また,配列でなくリストを用いるコンストラクタも用意されています。

ちなみに,試しにやってみたいけれどTextViewのみで構成されたレイアウトXMLファイルを作るのが面倒な場合,android.R.layout.textを使うといいと思います。



オブジェクトの文字情報をリストに表示

次のようなクラスを定義し,このクラスの文字情報をリスト内のセルに表示しします。

public class Person {
	private final String name;
	private final int age;

	Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

	@Override
	public String toString() {
		return String.format("名前:%s  年齢:%02d歳", name, age);
	}
}

アダプターの作成は以下の通りです。
(ActivityのonCreate内。thisはActivityのインスタンス)

Person[] persons = new Person[] {
	new Person("太郎", 25),
	new Person("次郎", 22),
	new Person("三郎", 19),
	new Person("四郎", 16),
	new Person("五郎", 13),
};

int itemLayoutId = R.layout.list_item_text_view;
ArrayAdapter<Person> adapter = new ArrayAdapter<Person>(this, itemLayoutId, persons);

これをListViewにセットすると先頭のセルには下記のように表示されます。
名前:太郎 年齢:25歳

二番目以降のセルも,それぞれのPerson型のインスタンスのtoStringの結果がセルに表示されています。

実は「オブジェクトの文字情報をリストに表示」のコンストラクタと,最初に紹介した「シンプルな使い方」のコンストラクタは同一のものです。
使っているコンストラクタの定義は,

ArrayAdapter(Context context, int resource, T[] objects)

となっています。
前者はString型を,後者はPerson型の配列をコンストラクタの引数として渡しています。
String[]型の場合も他の型の配列の場合も,セルの表示の際に表示するデータ要素のオジェクトのtoStringメソッドを呼び出しています。
そのため,任意の型の文字情報を表示したい場合,ToStringメソッドを実装すればその情報をセルに表示することが可能です。


リソースで定義した文字列配列を表示する

リソースファイル内に定義した下記のような文字列配列

res/values/arrays.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string-array name="day_array">
        <item>日曜日</item>
        <item>月曜日</item>
        <item>火曜日</item>
        <item>水曜日</item>
        <item>木曜日</item>
        <item>金曜日</item>
        <item>土曜日</item>
    </string-array>

</resources>

これをリストで表示するためのAdapterを作成します。
(ActivityのonCreate内。thisはActivityのインスタンス)

int itemLayoutId = R.layout.list_item_text_view;
int textArrayResId = R.array.day_array;
ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this, textArrayResId, itemLayoutId);

ArrayAdapterのクラスメソッドを用いてインスタンスを生成出来ました。
上記は3行ですが,実質1行で書けますね。


カスタマイズしたセル中にテキスト情報を表示する

下記のようなレイアウトXMLファイルを定義します。
res/layout/list_item_text_in_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="40dp" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_toLeftOf="@+id/label"
        android:text="曜日:" />

    <TextView
        android:id="@+id/label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Label" >
    </TextView>

    <ImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        android:layout_marginLeft="10dp"
        android:src="@drawable/ic_launcher" />

</RelativeLayout>

このレイアウトXMLファイルと,

ArrayAdapter(Context context, int resource, int textViewResourceId, T[] objects)

というコンストラクタを使います。(ActivityのonCreate内。thisはActivityのインスタンス)

String[] strings = new String[] {
	"日曜日", "月曜日", "火曜日", "水曜日", "木曜日", "金曜日", "土曜日"
};

int itemLayoutId = R.layout.list_item_text_in_layout;
int textViewId = R.id.label;
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, itemLayoutId, textViewId, strings);

ここで使っているコンストラクタは,第2引数にセルのレイアウトXMLファイルのidを,第3要素にセル内のTextViewのidを取ります。コンストラクタの第3引数で渡した配列の各要素の文字列は,第2要素で渡したidが示すTextView(ここではlabelというidのTextView)に表示されます。

これを使えば,セルに背景を設定したり,画像を複数個表示したり,他のTextViewを持つセルの表示も容易です。



まとめ

ArrayAdapter(もしくはBaseAdapter)のgetViewメソッドをオーバーライドしたり,内部にViewHolderを定義したり,セルのビューのタグにViewHolderをセットしたりして,リストを表示するのは,(定型パターンではありますが)やはり多少面倒です。
試しにささっとデータをリストで表示してみたい場合や,文字列のみが変わるリストを表示したい場合,ArrayAdapterを適切に使い少ないコード量でリストを作成すりことも可能です。


ただし,TextViewではなくImageViewの要素をセルごとに設定したい,セルごとに複数のTextViewの値を設定したい,画像と文字列両方セルごとに設定したい場合は,
getViewメソッドをオーバーライドするか,SimpleAdapterを使う必要があります。



参考:
http://developer.android.com/reference/android/widget/ArrayAdapter.html