Android Expandable list

In the meanwhile I have created an selector.xml as:

<?xml version="1.0" encoding="UTF-8"?>

<selector xmlns:android="schemas.android.com/apk/res/android" >

    <item
        android:drawable="@drawable/friend_small"
        android:state_expanded="true"/>

    <item android:drawable="@drawable/place_small"/>
</selector>

and given in android:groupIndicator="@drawable/selector" in xml – friend_small and place small are my images of expand and collapsed state


After a R & D over expandable List I found that expandable List-view is a two level tree view provided by Android.

This view contains two types of categories.

First type is Group-Elements and second one is Child-Elements, also called parent and child elements.

The main aim of this example is to customize the expandable list-view as the picture in the question shows.

I have covered some important topics about expandable list-view that I faced during my experiences.

Below code is main.xml contains the expandable list-view. main.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="fill_parent">

     <expandablelistview android:id="@+id/android:list" android:layout_width="fill_parent" android:layout_height="fill_parent" android:groupindicator="@drawable/group_indicator.xml">

     <textview android:id="@+id/android:empty" android:layout_width="fill_parent" android:layout_height="fill_parent" android:text="@string/main_no_items">       
</textview></expandablelistview></linearlayout>

the group_row.xml is as follows that contains the layout for Expandable list group view structure.group_row.xml ?

     <textview android:id="@+id/tvGroupName" android:layout_width="wrap_content" android:layout_height="40dip" android:textsize="16sp" android:textstyle="bold" android:paddingleft="30dip" android:gravity="center_vertical">

child_row.xml this is contains the layout for Expandable list view group structure. child_row.xml

<!--?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="40dip" android:gravity="center_vertical">

    <textview android:id="@+id/tvPlayerName" android:paddingleft="50dip" android:textsize="14sp" android:layout_width="wrap_content" android:layout_height="30dip" android:gravity="center_vertical">

</textview></linearlayout>

First read the reference of the expandable listview from xml to activity class.

 public class ExpList extends ExpandableListActivity
    {
     /**
      * strings for group elements
      */
        static final String arrGroupelements[] = 
        {
       "India",
       "Australia",
       "England",
       "South Africa"
     };

        /**
      * strings for child elements
      */
     static final String arrChildelements[][] = 
     {
       {
      "Sachin Tendulkar",
      "Raina",
      "Dhoni",
      "Yuvi"
       },
       {
      "Ponting",
      "Adam Gilchrist",
      "Michael Clarke"
       },
       {
      "Andrew Strauss",
      "kevin Peterson",
      "Nasser Hussain"
       },
       {
      "Graeme Smith",
      "AB de villiers",
      "Jacques Kallis"
       }
        };

     DisplayMetrics metrics;
     int width;
     ExpandableListView expList;

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

            expList = getExpandableListView();
            metrics = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(metrics);
            width = metrics.widthPixels;
            //this code for adjusting the group indicator into right side of the view


if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
            expList.setIndicatorBounds(width - GetDipsFromPixel(50), width - GetDipsFromPixel(10));
        } else {
            expList.setIndicatorBoundsRelative(width - GetDipsFromPixel(50), width - GetDipsFromPixel(10));
        }

            expList.setAdapter(new ExpAdapter(this));

      expList.setOnGroupExpandListener(new OnGroupExpandListener()
      {
       @Override
       public void onGroupExpand(int groupPosition) 
       {
        Log.e("onGroupExpand", "OK");
       }
      });

      expList.setOnGroupCollapseListener(new OnGroupCollapseListener()
      {
       @Override
       public void onGroupCollapse(int groupPosition) 
       {
        Log.e("onGroupCollapse", "OK");
       }
      });

      expList.setOnChildClickListener(new OnChildClickListener()
      {
       @Override
       public boolean onChildClick(ExpandableListView parent, View v,
         int groupPosition, int childPosition, long id) {
        Log.e("OnChildClickListener", "OK");
        return false;
       }
      });
        }

        public int GetDipsFromPixel(float pixels)
        {
         // Get the screen's density scale
         final float scale = getResources().getDisplayMetrics().density;
         // Convert the dps to pixels, based on density scale
         return (int) (pixels * scale + 0.5f);
        }
    }

For customising the Exp Listview main thing is adapter. Android provides BaseExpandableListAdapter for customising the view. Bellow is the code for design of Adapter.

This is adapter for expandable list-view for constructing the group and child elements.

public class ExpAdapter extends BaseExpandableListAdapter {

  private Context myContext;
  public ExpAdapter(Context context) {
   myContext = context;
  }
  @Override
  public Object getChild(int groupPosition, int childPosition) {
   return null;
  }

  @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) {
    LayoutInflater inflater =  (LayoutInflater) myContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    convertView = inflater.inflate(R.layout.child_row, null);
   }

   TextView tvPlayerName = (TextView) convertView.findViewById(R.id.tvPlayerName);
   tvPlayerName.setText(arrChildelements[groupPosition][childPosition]);

   return convertView;
  }

  @Override
  public int getChildrenCount(int groupPosition) {
   return arrChildelements[groupPosition].length;
  }

  @Override
  public Object getGroup(int groupPosition) {
   return null;
  }

  @Override
  public int getGroupCount() {
   return arrGroupelements.length;
  }

  @Override
  public long getGroupId(int groupPosition) {
   return 0;
  }

  @Override
  public View getGroupView(int groupPosition, boolean isExpanded,
    View convertView, ViewGroup parent) {

   if (convertView == null) {
    LayoutInflater inflater =  (LayoutInflater) myContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    convertView = inflater.inflate(R.layout.group_row, null);
   }

   TextView tvGroupName = (TextView) convertView.findViewById(R.id.tvGroupName);
   tvGroupName.setText(arrGroupelements[groupPosition]);

   return convertView;
  }

  @Override
  public boolean hasStableIds() {
   return false;
  }

  @Override
  public boolean isChildSelectable(int groupPosition, int childPosition) {
   return true;
  }
 }

group_indicator.xml This the code for changing the default indicator image.

 <?xml version="1.0" encoding="UTF-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:state_expanded="true" android:drawable="@drawable/friend_small" />
        <item android:drawable="@drawable/place_small" />
    </selector>

you can change the indicator by calling setGroupIndicator

Expandable lists are able to show an indicator beside each item to display the item's current state (the states are usually one of expanded group, collapsed group, child, or last child). Use setChildIndicator(Drawable) or setGroupIndicator(Drawable) (or the corresponding XML attributes) to set these indicators (see the docs for each method to see additional state that each Drawable can have).

also, you need your own implementation of an ExpandableListAdapter. it's possible to inflate your own views for both parents and children in it.