In this tutorial I will show you how to make a simple Expandable List.
1. Create a new project and call your java class(the one that is generated by Eclipse or other IDE) “MyActivity”.
2. Go to res – layout -main.xml and put the following code:
<?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="fill_parent" > <ExpandableListView android:id="@+id/expandable_list" android:layout_width="fill_parent" android:layout_height="fill_parent" android:transcriptMode="alwaysScroll" android:cacheColorHint="#00000000" android:listSelector="@android:color/transparent"/> </LinearLayout>
NOTE: The attribute “android:transcriptMode=”alwaysScroll”” will make your expandable list always to scroll to the end of the list when you want to expand or collapse a group. If you do not want this set it this way: “android:transcriptMode=”disabled“. Now when you expand a group the list will scroll to the group that is expanded.
3. Now create another 2 xml files in res – layout, one called list_item_parent.xml and the other one called list_item_child.xml.
- The xml code for list_item_parent.xml file is:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent" android:descendantFocusability="blocksDescendants" android:id="@+id/list_item"> <TextView android:layout_width="0dp" android:layout_height="wrap_content" android:id="@+id/list_item_text_view" android:textSize="20sp" android:padding="10dp" android:layout_weight="1" android:layout_marginLeft="35dp" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="button" android:focusable="false" android:layout_gravity="right" android:focusableInTouchMode="false" android:id="@+id/button"/> </LinearLayout>
NOTE: If you put a button on the parent the group will not expand anymore, so in order to make the group expand when you have a button you must set its focus to FALSE. Also, if that doesn’t work, it should work with:
android:descendantFocusability="blocksDescendants"
- The xml code for list_item_child.xml file is:
<?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="fill_parent" android:id="@+id/list_item_child" android:gravity="center_vertical"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/list_item_text_child" android:textSize="20sp" android:padding="10dp" android:layout_marginLeft="5dp"/> </LinearLayout>
4. Now create a new java class and call it “Parent”. In this class we will store the data about the parent: the name and the children (an array list of children). After you create the class put the following code:
import java.util.ArrayList; public class Parent { private String mTitle; private ArrayList<String> mArrayChildren; public String getTitle() { return mTitle; } public void setTitle(String title) { mTitle = title; } public ArrayList<String> getArrayChildren() { return mArrayChildren; } public void setArrayChildren(ArrayList<String> arrayChildren) { mArrayChildren = arrayChildren; } }
5. At this step you have to create the adapter for the expandable list. To do this, create a new java class called “MyCustomAdapter” and put the following code:
import android.content.Context; import android.database.DataSetObserver; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; import android.widget.Button; import android.widget.TextView; import java.util.ArrayList; public class MyCustomAdapter extends BaseExpandableListAdapter { private LayoutInflater inflater; private ArrayList<Parent> mParent; public MyCustomAdapter(Context context, ArrayList<Parent> parent){ mParent = parent; inflater = LayoutInflater.from(context); } @Override //counts the number of group/parent items so the list knows how many times calls getGroupView() method public int getGroupCount() { return mParent.size(); } @Override //counts the number of children items so the list knows how many times calls getChildView() method public int getChildrenCount(int i) { return mParent.get(i).getArrayChildren().size(); } @Override //gets the title of each parent/group public Object getGroup(int i) { return mParent.get(i).getTitle(); } @Override //gets the name of each item public Object getChild(int i, int i1) { return mParent.get(i).getArrayChildren().get(i1); } @Override public long getGroupId(int i) { return i; } @Override public long getChildId(int i, int i1) { return i1; } @Override public boolean hasStableIds() { return true; } @Override //in this method you must set the text to see the parent/group on the list public View getGroupView(int groupPosition, boolean b, View view, ViewGroup viewGroup) { ViewHolder holder = new ViewHolder(); holder.groupPosition = groupPosition; if (view == null) { view = inflater.inflate(R.layout.list_item_parent, viewGroup,false); } TextView textView = (TextView) view.findViewById(R.id.list_item_text_view); textView.setText(getGroup(groupPosition).toString()); view.setTag(holder); //return the entire view return view; } @Override //in this method you must set the text to see the children on the list public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View view, ViewGroup viewGroup) { ViewHolder holder = new ViewHolder(); holder.childPosition = childPosition; holder.groupPosition = groupPosition; if (view == null) { view = inflater.inflate(R.layout.list_item_child, viewGroup,false); } TextView textView = (TextView) view.findViewById(R.id.list_item_text_child); textView.setText(mParent.get(groupPosition).getArrayChildren().get(childPosition)); view.setTag(holder); //return the entire view return view; } @Override public boolean isChildSelectable(int i, int i1) { return true; } @Override public void registerDataSetObserver(DataSetObserver observer) { /* used to make the notifyDataSetChanged() method work */ super.registerDataSetObserver(observer); } // Intentionally put on comment, if you need on click deactivate it /* @Override public void onClick(View view) { ViewHolder holder = (ViewHolder)view.getTag(); if (view.getId() == holder.button.getId()){ // DO YOUR ACTION } }*/ protected class ViewHolder { protected int childPosition; protected int groupPosition; protected Button button; } }
6. Now go to the MyActivity and put the following code:
import android.app.Activity; import android.app.ExpandableListActivity; import android.os.Bundle; import android.widget.ExpandableListView; import java.util.ArrayList; public class MyActivity extends Activity { private ExpandableListView mExpandableList; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); mExpandableList = (ExpandableListView)findViewById(R.id.expandable_list); ArrayList<Parent> arrayParents = new ArrayList<Parent>(); ArrayList<String> arrayChildren = new ArrayList<String>(); //here we set the parents and the children for (int i = 0; i < 10; i++){ //for each "i" create a new Parent object to set the title and the children Parent parent = new Parent(); parent.setTitle("Parent " + i); arrayChildren = new ArrayList<String>(); for (int j = 0; j < 10; j++) { arrayChildren.add("Child " + j); } parent.setArrayChildren(arrayChildren); //in this array we add the Parent object. We will use the arrayParents at the setAdapter arrayParents.add(parent); } //sets the adapter that provides data to the list. mExpandableList.setAdapter(new MyCustomAdapter(MyActivity.this,arrayParents)); } }
Now the result should look like this:
If you want to see the source code, please visit our GitHub repo here. There you can see a working project that might help you get started with ExpandableListView.