ExpandableListを使った折り畳みリストの作り方
リスト中の項目をクリックするとその項目内の子アイテムが展開されるようなリストを作るにはExpandableListViewを使います。
ExpandableListは普通のリストと違い、ExpandableListAdapterを継承したクラスをアダプターとして設定します。その手順は次の通りです。
- グループアイテムと子アイテムのレイアウトの作成
- アダプタークラスの作成
- リストにアダプタークラスを渡す
グループアイテムと子アイテムのレイアウトの作成
初めにExpandableListの直近のグループアイテムのレイアウトを作ります。
expandable_list_group_item.xml
<?xml version="1.0" encoding="utf-8" ?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants"
android:orientation="vertical" >
<TextView
android:id="@+id/expand_list_group_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:textSize="24sp" />
</LinearLayout>
この例ではテキストビュー1つだけを設置しています。
次に子アイテムのレイアウトを次のように作成します。
expandable_list_child_item.xml
<?xml version="1.0" encoding="utf-8" ?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="blocksDescendants"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingLeft="10dp" >
<ImageView
android:id="@+id/expand_list_child_image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="3dp" />
<TextView
android:id="@+id/expand_list_child_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView"
android:textSize="21sp" />
</LinearLayout>
子アイテムには画像とテキストの2つを表示させたいので、左にImageView、右にTextViewを設置したレイアウトを作成しました。
アダプタークラスの作成
次にリストビューを表示するアクティビティやフラグメントクラス内で次のようにBaseExpandableListAdapterを拡張したアダプタークラスを作ります。
MainActivity.javapublic class MainActivity extends Activity { int groupNum = 3; String groupTexts[] = new String[groupNum]; //グループアイテムに表示するテキスト int childNum = 5; String childTexts[][] = new String[groupNum][]; //子アイテムに表示するテキスト Bitmap childImages[][] = new Bitmap[groupNum][]; //子アイテムに表示するテキスト @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } /**折り畳みリストに設定するアダプタークラス*/ public class MyExpandListAdapter extends BaseExpandableListAdapter { private LayoutInflater inflater = (LayoutInflater) MainActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE); /**子アイテムのテキストを取得*/ @Override public Object getChild(int groupPosition, int childPosition) { return childTexts[groupPosition][childPosition]; } /**子アイテムの画像を取得*/ public Bitmap getChildImage(int groupPosition, int childPosition) { return childImages[groupPosition][childPosition]; } @Override public long getChildId(int groupPosition, int childPosition) { return 0; } /**子アイテムの取得(なければ作る)*/ @Override public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) { if(convertView == null){ convertView = inflater.inflate(R.layout.expandable_list_child_item, null); } final ImageView imageView = (ImageView) convertView.findViewById( R.id.expand_list_child_image_view); final TextView textView = (TextView) convertView.findViewById( R.id.expand_list_child_text); imageView.setImageBitmap(getChildImage(groupPosition,childPosition)); textView.setText((CharSequence) getChild(groupPosition, childPosition)); return convertView; } @Override public int getChildrenCount(int groupPosition) { return childNum; } /**グループのテキストを取得*/ @Override public Object getGroup(int groupPosition) { return groupTexts[groupPosition]; } @Override public int getGroupCount() { return groupNum; } @Override public long getGroupId(int groupPosition) { return 0; } /**リスト内の1つのグループの作成*/ @Override public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) { if(convertView == null){ convertView = inflater.inflate(R.layout.expndable_list_group_item, null); } final TextView groupText = (TextView) convertView.findViewById( R.id.expand_list_group_text); groupText.setText((CharSequence) getGroup(groupPosition)); return convertView; } @Override public boolean hasStableIds() { return true; } @Override public boolean isChildSelectable(int groupPosition, int childPosition) { return true; } } }
getGroupViewとgetChildViewという2つのメソッド内でそれぞれグループアイテムとその子アイテムをレイアウトから生成しています。
この例ではグループアイテムに表示するテキストをgroupTextsというString型の配列で、子アイテムの画像とテキストをchildTextsというString配列とchildImagesというBitmap配列で宣言しています。
そしてアイテムのテキストや画像をこの配列から取り出しています。リストビューが保持するデータの内容によって配列の型は変わりますが、子アイテムのデータ配列はgetChildメソッドなどでデータを取得するときのために2次元配列にしておいた方がグッドです。
リストビューへのアダプターの設置
最後にアダプタークラスをリストビューに設定します。たとえば先ほどアダプタークラスを作った同じアクティビティクラスのonCreateViewメソッドなどでデータ配列を宣言してからアダプタークラスを作ってリストに設定します。
MainActivity.java@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ExpandableListView myExpandableList = (ExpandableListView)findViewById(R.id.my_expandable_list); /**リストのグループと子アイテムのデータ配列の初期化*/ for(int gi = 0; gi < groupNum; ++gi){ groupTexts[gi] = "Group" + (gi + 1); childTexts[gi] = new String[childNum]; childImages[gi] = new Bitmap[childNum]; for(int ci = 0; ci < childNum; ++ci){ childTexts[gi][ci] = "Child Item" + (ci + 1); childImages[gi][ci] = BitmapFactory.decodeResource(getResources(), R.drawable.child_item); } } MyExpandListAdapter myAdapter = new MyExpandListAdapter(); anmExpandList.setAdapter(myAdapter); //アダプターを設定 /**子アイテムがクリックされたときのリスナー*/ anmExpandList.setOnChildClickListener(new ExpandableListView.OnChildClickListener() { @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { Toast.makeText(this, "グループ" + (groupPosition + 1) + "の子アイテム" + (childPosition + 1) + "が押されました。", Toast.LENGTH_LONG).show(); return false; } }); /**グループアイテムがクリックされたときのリスナー*/ anmExpandList.setOnGroupClickListener(new ExpandableListView.OnGroupClickListener() { @Override public boolean onGroupClick(ExpandableListView parent, View v, int groupPosition, long id) { Toast.makeText(this, "グループ" + (groupPosition + 1) + "が押されました。" , Toast.LENGTH_LONG).show(); return false; } }); } /**折り畳みリストに設定するアダプタークラス*/ public class MyExpandListAdapter extends BaseExpandableListAdapter { /*中略*/ } }
アダプターインスタンスを作る前にグループと子アイテムに設定するStringやBitmap配列をグループと子アイテムの数だけ初期化しています。
あとはアダプターを設定して子アイテムやグループがクリックされたらどのアイテムがクリックされたかのトーストを表示しているだけです。