ExpandableListを使った折り畳みリストの作り方

リスト中の項目をクリックするとその項目内の子アイテムが展開されるようなリストを作るにはExpandableListViewを使います。

ExpandableListは普通のリストと違い、ExpandableListAdapterを継承したクラスをアダプターとして設定します。その手順は次の通りです。

  1. グループアイテムと子アイテムのレイアウトの作成
  2. アダプタークラスの作成
  3. リストにアダプタークラスを渡す

グループアイテムと子アイテムのレイアウトの作成

初めに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.java
public 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配列をグループと子アイテムの数だけ初期化しています。

あとはアダプターを設定して子アイテムやグループがクリックされたらどのアイテムがクリックされたかのトーストを表示しているだけです。

3つのグループと5つの子アイテムが表示された折り畳みリスト
関連項目
プライバシーポリシー