2011年11月22日火曜日

ListViewの折り畳み

ListViewについて色々とやってきましたが、今回で最後にします。

ListViewはリストを画面に表示するクラスでしたが、
リストを選択すると更にリストが表示される、
階層表示を実装してみます。

まずはJavaのコードです。
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.ExpandableListAdapter;
import android.widget.ExpandableListView;
import android.widget.SimpleExpandableListAdapter;
import android.widget.Toast;

public class ListView11 extends Activity{

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);

  // ExpandableListViewインスタンスを取得
  ExpandableListView listView =
    (ExpandableListView) findViewById(R.id.list);

  // 親のリストを格納するArrayListインスタンスを生成
  List<Map<String, Object>> parentsList =
    new ArrayList<Map<String, Object>>();

  // parentsListにデータを追加
  parentsList.add(getParentData("親1"));
  parentsList.add(getParentData("親2"));

  // 子のリストを格納するArrayListインスタンスを生成
  List<List<Map<String, Object>>> childrenList =
    new ArrayList<List<Map<String, Object>>>();

  // 子リストにデータを追加
  childrenList.add(getChildList("子1-1", "子1-2")); // 親1に対応
  childrenList.add(getChildList("子2-1", "子2-2")); // 親2に対応

  // SimpleExpandableListAdapterインスタンスを生成
  SimpleExpandableListAdapter adapter = new SimpleExpandableListAdapter(
    this,
    parentsList,
    android.R.layout.simple_expandable_list_item_1,
    new String[]{"parent_text"},
    new int[]{android.R.id.text1},
    childrenList,
    R.layout.row,
    new String[]{"child_text"},
    new int[]{R.id.child_text}
  );

  // 作成したアダプタをExpandableListViewにセットする
  listView.setAdapter(adapter);

  // クリック時のリスナを設定
  listView.setOnChildClickListener(
    new ExpandableListView.OnChildClickListener() {

   @SuppressWarnings("unchecked") // ジェネリクスを使用したキャストの為
   @Override
   public boolean onChildClick(
     ExpandableListView parent,
     View view,
     int groupPosition,
     int childPosition,
     long id) {

    // アダプタからデータを取得してトーストで表示
    ExpandableListAdapter adapter = parent.
      getExpandableListAdapter();
    Map<String, Object> childMap = (Map<String, Object>)adapter.
      getChild(groupPosition, childPosition);
    Toast.makeText(
      ListView11.this,
      childMap.get("child_text").toString(),
      Toast.LENGTH_SHORT
    ).show();
    return false;
   }
  });
 }

 /**
  * 親リストに格納するデータを返す
  *
  * @param object  親リストに格納するMapのvalue値
  * @return parentData 親リストに格納するMap
  */
 private Map<String, Object> getParentData(Object object) {
  Map<String, Object> parentData = new HashMap<String, Object>();
  parentData.put("parent_text", object);
  return parentData;
 }

 /**
  * 子リストに格納するデータを返す
  *
  * @param object  子リストに格納するMapのvalue値の配列
  * @return childList 子リストに格納するList
  */
 private List<Map<String, Object>> getChildList(Object... object) {
  List<Map<String, Object>> childList =
    new ArrayList<Map<String, Object>>();

  // 引数に渡されたオブジェクトの数だけ子リストを追加
  for (Object o : object) {
   Map<String, Object> childData = new HashMap<String, Object>();
   childData.put("child_text", o);
   childList.add(childData);
  }
  return childList;
 }
}
長ったるいコードですが、やっている事は単純です。

1. ExpandableListViewクラスのインスタンスを生成(22行目)
⇒これが画面に表示されるリストの骨格です。
名前の通りListViewを継承しています。

2. SimpleExpandableListAdapterクラスのインスタンスを生成(42行目)
⇒ExpandableListViewに値をセットする為のアダプタ。
親リストと子リストをコンストラクタで渡してやる事で、
階層表示を可能にします。

3. ExpandableListViewにSimpleExpandableListAdapterをセット(55行目)
⇒作成したアダプタをリストビューに設定する事で、
親リストと子リストが格納されます。

その他にクリックリスナーを設定していたり、
privateなメソッドで親リストや子リストの生成を行っていますが、
今回の主題であるリストの階層表示には直接関係ありません。。。

続いて"res/layout/main.xml"のコードです。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/parent"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
>
<ExpandableListView
    android:id="@+id/list"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
/>
</LinearLayout>
ここで設定しているExpandableListViewが親リストとなります。

"res/layout/row.xml"のコードです。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
>
<TextView
    android:id="@+id/child_text"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
/>
</LinearLayout>
TextViewが子リストの要素となります。


上記のコードを実行すると、次のように表示されます。

親リストをタップする事で子リストが表示されます。

今回は親リストに対して、子リストを2件ずつ設定しましたが、
子リストにあたるArrayListの要素数だけ表示する事が可能です。


ListViewを4回程学習してきましたが、
各パターンごとに専用のアダプタが用意されており、
使い方さえわかれば初心者のsirocoでも実装は難しくないと感じました。

色々なAPIが用意されているのもAndroidの良いところですね~
次回はアプリには大抵用意されている「設定画面」を作ってみたいと思います。

0 件のコメント:

コメントを投稿