-
Notifications
You must be signed in to change notification settings - Fork 355
2.06. ListView と ViewPager
この章では、ListView と ViewPager の2つの特殊な View について解説します。
参考:Building Layouts with an Adapter | Android Developers
参考:Making ListView Scrolling Smooth | Android Developers
- ListView - ListAdapter - ListViewを表示する - カスタマイズしたリストアイテムを表示する - Viewの再利用について - ListViewの描画処理について
- ViewPager - PagerAdapter
ListView は、縦にスクロールする一覧表示のための View です。
ListView 自身には、一覧の中身を管理する機能はありません。
代わりに、Adapter という仕組みを用いて、データソースの管理と、データの View へのバインドをさせ、ListView は、スクロール位置に合わせて必要な View を Adapter から取り出すことをします。
リストデータは、List インタフェースを実装したデータソースや、或いは、データベースへ問い合わせた結果のデータソースである場合もあります。
データをバインドして表示する際には、ListAdapterインタフェースを実装したAdapterを使用します。
Adapterにはいくつかの種類が提供されています。以下はその一部となります。
名前 | 役割 |
---|---|
ArrayAdapter | 配列やリストデータソースをバインドする際に使用します。 |
SimpleCursorAdapter | データベースへ問い合わせた結果をバインドする際に使用します。 |
ListViewを表示するには以下の作業が必要となります。
- ListViewをレイアウトxmlに配置
- ListViewにAdapterをセットする
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<!-- ListViewを配置 -->
<ListView
android:id="@+id/ListView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mActivity = this;
// ListViewに表示するデータを作成する
ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < 20; i++) {
list.add("hoge" + i);
}
ListView listView = (ListView) findViewById(R.id.ListView);
// android.R.layout.simple_list_item_1はAndroidで既に定義されているリストアイテムのレイアウトです
ArrayAdapter<String> adapter = new ArrayAdapter<String>(mActivity,
android.R.layout.simple_list_item_1, list);
listView.setAdapter(adapter);
// タップした時の動作を定義する
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// Adapterからタップした位置のデータを取得する
String str = (String) parent.getItemAtPosition(position);
Toast.makeText(mActivity, str, Toast.LENGTH_SHORT).show();
}
});
}
まずはArrayAdapterのインスタンスを作成します。
ここではコンストラクタの引数にContextとリストアイテムのレイアウトIDと表示するデータをリスト形式で渡しています。
ArrayAdapterには様々なコンストラクタが用意されています。適宜、適切なものを使用すると良いでしょう。
レイアウトIDにはandroid.R.layout.simple_list_item_1を設定しています。これはAndroidで用意されているリストアイテムのレイアウトです。中にはTextViewが1つあるだけです。
表現豊かたなレイアウトを使用したい場合、自分で作成したレイアウトをリストアイテムに表示することもできます。
その方法は次項リストアイテムをカスタマイズするにて説明します。
次に、setAdapterメソッドでListViewにAdapterをセットします。
最後に、setOnItemClickListenerメソッドでリストをタップした時の動作を設定しています。
実行すると以下の様なListViewが表示されます。
カスタマイズしたリストアイテムを表示するには以下の作業が必要となります。
- リストアイテムのレイアウトxmlの作成
- 独自Adapterの作成
新規にレイアウトxmlを作成します。
リストアイテムのレイアウトは以下のように作成します。
custom_list_item.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="4dp" >
<ImageView
android:id="@+id/imageView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:src="@drawable/ic_launcher" />
<TextView
android:id="@+id/TitleText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_toRightOf="@+id/imageView1"
android:textSize="18sp" />
<TextView
android:id="@+id/SubTitleText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/TitleText"
android:layout_alignParentRight="true"
android:layout_below="@+id/TitleText" />
</RelativeLayout>
Adapter内ではリストアイテムの生成と表示位置に対応するデータの取得、設定といった処理を行います。
CustomListItemAdapter.java
public class CustomListItemAdapter extends ArrayAdapter<String> {
private LayoutInflater mLayoutInflater;
public CustomListItemAdapter(Context context, List<String> objects) {
// 第2引数はtextViewResourceIdとされていますが、カスタムリストアイテムを使用する場合は特に意識する必要のない引数です
super(context, 0, objects);
// レイアウト生成に使用するインフレーター
mLayoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
// ListViewに表示する分のレイアウトが生成されていない場合レイアウトを作成する
if (convertView == null) {
// レイアウトファイルからViewを生成する
view = mLayoutInflater.inflate(R.layout.custom_list_item, parent, false);
} else {
// レイアウトが存在する場合は再利用する
view = convertView;
}
// リストアイテムに対応するデータを取得する
String item = getItem(position);
// 各Viewに表示する情報を設定
TextView text1 = (TextView) view.findViewById(R.id.TitleText);
text1.setText("Title:" + item);
TextView text2 = (TextView) view.findViewById(R.id.SubTitleText);
text2.setText("SubTitle:" + item);
return view;
}
}
ArrayAdapterを継承して独自のAdapterを作成しています。
getViewメソッドをオーバーライドして、戻り値に表示するリストアイテムのViewを返します。
表示している位置のデータはgetItemメソッドで取得することができます。
Androidではリストアイテムを表示する際に、既にViewが生成されていてる場合はそれを再利用します。
リストに表示するデータが50件あった場合、リストアイテムのViewを50個を生成することはしないということです。
画面を構成するのに必要な分のViewが生成され、あとは再利用するため無駄なViewを生成するといったことはありません。
どのようにViewが再利用されているかを確認するため先ほどのCustomListItemAdapterクラスのgetViewメソッドを以下のように修正します。
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = null;
// ListViewに表示する分のレイアウトが生成されていない場合レイアウトを作成する
if (convertView == null) {
// レイアウトファイルからViewを生成する
view = mLayoutInflater.inflate(R.layout.custom_list_item, parent, false);
// リストアイテムに対応するデータを取得する
String item = getItem(position);
// 各Viewに表示する情報を設定
TextView text1 = (TextView) view.findViewById(R.id.TitleText);
text1.setText("Title:" + item);
TextView text2 = (TextView) view.findViewById(R.id.SubTitleText);
text2.setText("SubTitle:" + item);
} else {
// レイアウトが存在する場合は再利用する
view = convertView;
}
// 一度作成したレイアウトの表示データを変更しないことにより、再利用されたデータがどこに表示されるかを確認する
return view;
}
実行すると以下のようにViewが使いまわされていることがわかります。
ListViewがスクロールされるたびにfindViewByIdメソッドを呼び出すとパフォーマンスが低下します。
再利用したViewを表示するときでも各要素を更新することがあります。
頻繁にfindViewByIdメソッドを呼び出す場合には"view holder"デザインパターンを利用すると良いです。
ViewPager は、横にフリックして View を切り替えるための View です。
単純な View だけでなく、Fragment を持たせて、複数の Fragment を切り替える用途にも使用出来ます。
ViewPager も、ListView と同じく、Adapter に中身を管理させます。
Portions of this page are reproduced from work created and shared by the Android Open Source Project and used according to terms described in the Creative Commons 2.5 Attribution License.