Android ExpandableListView

Android ExpandableListView Tutorial and Examples.

An ExpandableListView is a view that shows items in a vertically scrolling two-level list. You can imagine it’s a form of a ListView given the name or the fact that it derives from it, however ExpandableListView is obviously more complex in that it’s view items can be expanded and collapsed.

It allows two levels:

  1. groups which can individually be expanded
  2. children shown when the groups are expanded.

Powering ExpandableListView is the ExpandableListAdapter. It is this adapter that supplies items to populate our ExpandableListView.

===

ExpandableListView API Definition.

ExpandableListView isn’t young, even if alot of developers haven’t used it yet. It has existed since the beginning of android, API level 1.

As a class it derives from [ListView](/android/listview:

public class ExpandableListView extends ListView 

Both reside in the android.widget package.

Here’s ExpandableListView‘s inheritance hierarchy:

java.lang.Object
   ↳    android.view.View
       ↳    android.view.ViewGroup
           ↳    android.widget.AdapterView<android.widget.ListAdapter>
               ↳    android.widget.AbsListView
                   ↳    android.widget.ListView
                       ↳    android.widget.ExpandableListView

States and Indicators

Beside the item views in your ExpandableListView normally you see an indicator. This visually notifies you that you need to either expand to see more content or close the child. They tell you the current state of the expandable listview.

These states can be:

  1. Expanded group.
  2. Collapsed group
  3. Child
  4. Last child).

These indicators can be set using the setChildIndicator(Drawable) or setGroupIndicator(Drawable) (or the corresponding XML attributes).

The default style for an ExpandableListView provides indicators which will be shown next to Views given to the ExpandableListView.

The layouts android.R.layout.simple_expandable_list_item_1 and android.R.layout.simple_expandable_list_item_2 (which should be used with SimpleCursorTreeAdapter) contain the preferred position information for indicators.

You can find more documentation about ExpandableListView here.

 

Share

Related Concepts

1 Example

  1. Android ExpandableListView with Images and Text

    Android ExpandableListView tutorial with images and text tutorial.

    Everyone knows and loves android listviews.However, listviews have a more powerful sister known as ExpandableListeView. These are views that show items in a vertically scrolling two-level list.

    This is powerful when you want to group items in a list. The items groups can be expanded to show their children, which are also lists themselves. ExpandableListViews should not be confused with accordions.

    They are lists inside list items. ExpandableListView items come from ExpandableListAdapter. ExpandableListViews do derive from ListViews, hence having the flexibility and capability of Listviews themselves.

    They are simply ListViews nested inside ListView Items. They were added to android in API Level 1, so have actually been around for along time even though most people are obsessed with ListViews and RecyclerViews.

    What is ExpandableListView?

    An ExpandableListView is a view that shows items in a vertically scrolling two-level list. You can imagine it’s a form of a ListView given the name or the fact that it derives from it, however ExpandableListView is obviously more complex in that it’s view items can be expanded and collapsed.

    It allows two levels:

    1. groups which can individually be expanded
    2. children shown when the groups are expanded.

    Powering ExpandableListView is the ExpandableListAdapter. It is this adapter that supplies items to populate our ExpandableListView.

    In this tutorial, we look at ExpandableListView with images and text. You can find more details about ExpandableListViews here.

    Screenshot
    • Here’s the screenshot of the project.

    ExpandableListView Android Android ExpandableListView

    • Android ExpandableListView example.
    • Show expandableListView with images and text in android.
    • Android Eclipse tutorial.
    • Group items with expandableListView.

    Tools Used

    This example was written with the following tools:

    1. Operating System : Windows 7
    2. IDE : Eclipse IDE
    3. Language : Java

    Advantages of ExpandableListViews

    No. Advantage
    1. It is the easiest way to show grouped items in android development.
    2. It is an inbuilt adapterview hence no need for third party libraries.ExpandableListViews have existed since the very first version of Android.
    3. It’s as customizable and as powerful as ListViews since it’s actually the latter’s child.

    1. Create User Interface

    User interfaces are typically created in android using XML layouts as opposed by direct java coding.

    This is an example fo declarative programming.

    ######### Advantages of Using XML over Java

    No. Advantage
    1. Declarative creation of widgets and views allows us to use a declarative language XML which makes is easier.
    2. It’s easily maintanable as the user interface is decoupled from your Java logic.
    3. It’s easier to share or download code and safely test them before runtime.
    4. You can use XML generated tools to generate XML

    Here are our layouts for this project:

    (a). activity_main.xml
    • This layout gets inflated to MainActivity user interface.
    • It includes the content_main.xml.
    • We add our ExpandableListView here.

    Here are the roles of this layout:

    No. Responsibility
    1. Hold an ExpandableListeView which is our adapterview.
    2. Be ready to be for inflation of into a view object. Then that view object gets set as the contentview of the Main activity.
    <RelativeLayout 
        
        android_layout_width="match_parent"
        android_layout_height="match_parent"
        android_paddingBottom="@dimen/activity_vertical_margin"
        android_paddingLeft="@dimen/activity_horizontal_margin"
        android_paddingRight="@dimen/activity_horizontal_margin"
        android_paddingTop="@dimen/activity_vertical_margin"
        tools_context=".MainActivity" >
    
        <ExpandableListView
            android_id="@+id/expandableListView1"
            android_layout_width="match_parent"
            android_layout_height="wrap_content"
            android_layout_alignParentLeft="true"
            android_layout_alignParentTop="true" >
        </ExpandableListView>
    
    </RelativeLayout>
    (b). team.xml

    This layout represents a single team.

    Here are the roles of this layout.

    No. Role
    1. Define an ImageView and TextView that will be show alongside each other to provide both the team flag and name respectively.
    2. Align them horizontally using a LinearLayout.
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 
        android_layout_width="match_parent"
        android_layout_height="match_parent"
        android_orientation="horizontal" >
    
        <ImageView
            android_id="@+id/imageView1"
            android_layout_width="56dp"
            android_layout_height="56dp"
            android_src="@drawable/arrow" />
    
        <TextView
            android_id="@+id/textView1"
            android_layout_width="wrap_content"
            android_layout_height="wrap_content"
            android_text="Team"
            android_textAppearance="?android:attr/textAppearanceMedium" />
    
    </LinearLayout>

    (c). Our Player XML(player.xml)

    • The xml definition of player which is our child in the expandableListView.

    Here the roles of player.xml layout:

    No. Responsibility
    1. Specify an imageview and textview to be used to present a single soccer player object.
    2. Be ready to be inflated into children in the ExpandableListView.
    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout 
        android_layout_width="match_parent"
        android_layout_height="match_parent"
        android_orientation="horizontal" >
    
        <ImageView
            android_id="@+id/imageView1"
            android_layout_width="wrap_content"
            android_layout_height="wrap_content"
            android_layout_alignParentLeft="true"
            android_layout_alignParentTop="true"
            android_layout_marginLeft="24dp"
            android_src="@drawable/mata" />
    
        <TextView
            android_id="@+id/textView1"
            android_layout_width="wrap_content"
            android_layout_height="wrap_content"
            android_layout_alignParentTop="true"
            android_layout_marginLeft="14dp"
            android_layout_marginTop="21dp"
            android_layout_toRightOf="@+id/imageView1"
            android_text="player"
            android_textAppearance="?android:attr/textAppearanceMedium" />
    
    </RelativeLayout>

    2. Team.java

    •  This is the definition of a team object.
    • It specifies the teams’ properties.

    Here are the roles of this class:

    No. Responsibility
    1. Act as the data object class for teams to be shown in our ExpandableListView.
    2. Define 3 public properties of each team: a name, an image and the player names in that team.
    package com.tutorials.expandable_view;
    
    import java.util.ArrayList;
    
    public class Team {
    
      //PROPERTIES OF A SINGLE TEAM
        public String Name;
        public String Image;
        public ArrayList<String> players=new ArrayList<String>();
    
        public Team(String Name)
        {
          this.Name=Name;
        }
    
        @Override
        public String toString() {
          // TODO Auto-generated method stub
          return Name;
        }
    }

    3. CustomAdapter.java

    This is our ExpandableListAdapter class. It derives from android.widget.BaseExpandableListAdapter.

    Here are the main responsibilities of this class:

    No. Responsibility
    1. Maintain three private instance fields, a Context, an ArrayList to hold teams, and a LayoutInflater object to assist in the inflation of our player.xml and team.xml layouts.
    2. Receive a Context object and an ArrayList and assign them to our private instance fields.
    3. Override the getChild() of our ExpandableListAdapter and return a single player object from a particular team.
    4. Override the getChildId() of our ExpandableListAdapter and return an integer to be used as child ID.
    5. Override the getChildView() of our ExpandableListAdapter, inflate our player.xml inside it and return a view object.
    6. Override the getChildrenCount() of our ExpandableListAdapter and return the total number of children in a given team.
    7. Override the getGroup() of our ExpandableListAdapter and return a single team object where a particular player plays for.
    8. Override the getGroupCount() of our ExpandableListAdapter and return the total number of groups to be rendered in our ExpandableListView.
    9. Override the getGroupView() of our ExpandableListAdapter, inflate our team.xml inside it and return the resultant view object.
    10. Tell our ExpandableListAdapter that our IDs are not stable and that we want to want our ExpandableListView children to be selectable.
    package com.tutorials.expandable_view;
    
    import java.util.ArrayList;
    
    import android.content.Context;
    import android.graphics.Color;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseExpandableListAdapter;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    public class CustomAdapter extends BaseExpandableListAdapter {
    
      private Context c;
      private ArrayList<Team> team;
      private LayoutInflater inflater;
    
      public CustomAdapter(Context c,ArrayList<Team> team)
      {
        this.c=c;
        this.team=team;
        inflater=(LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
      }
    
      //GET A SINGLE PLAYER
      @Override
      public Object getChild(int groupPos, int childPos) {
        // TODO Auto-generated method stub
        return team.get(groupPos).players.get(childPos);
      }
    
      //GET PLAYER ID
      @Override
      public long getChildId(int arg0, int arg1) {
        // TODO Auto-generated method stub
        return 0;
      }
    
      //GET PLAYER ROW
      @Override
      public View getChildView(int groupPos, int childPos, boolean isLastChild, View convertView,
          ViewGroup parent) {
    
        //ONLY INFLATER XML ROW LAYOUT IF ITS NOT PRESENT,OTHERWISE REUSE IT
    
        if(convertView==null)
        {
          convertView=inflater.inflate(R.layout.player, null);
        }
    
        //GET CHILD/PLAYER NAME
        String  child=(String) getChild(groupPos, childPos);
    
        //SET CHILD NAME
        TextView nameTv=(TextView) convertView.findViewById(R.id.textView1);
        ImageView img=(ImageView) convertView.findViewById(R.id.imageView1);
    
        nameTv.setText(child);
    
        //GET TEAM NAME
        String teamName= getGroup(groupPos).toString();
    
        //ASSIGN IMAGES TO PLAYERS ACCORDING TO THEIR NAMES AN TEAMS
        if(teamName=="Man Utd")
        {
          if(child=="Wayne Rooney")
          {
            img.setImageResource(R.drawable.rooney) ;
          }else if(child=="Ander Herera")
          {
            img.setImageResource(R.drawable.herera) ;
          }else if(child=="Van Persie")
          {
            img.setImageResource(R.drawable.vanpersie)  ;
          }else if(child=="Juan Mata")
          {
            img.setImageResource(R.drawable.mata)   ;
          }
        }else if(teamName=="Chelsea")
        {
          if(child=="John Terry")
          {
            img.setImageResource(R.drawable.terry)  ;
          }else if(child=="Eden Hazard")
          {
            img.setImageResource(R.drawable.hazard) ;
          }else if(child=="Oscar")
          {
            img.setImageResource(R.drawable.oscar)  ;
          }else if(child=="Diego Costa")
          {
            img.setImageResource(R.drawable.costa)  ;
          }
        }else if(teamName=="Arsenal")
        {
          if(child=="Jack Wilshere")
          {
            img.setImageResource(R.drawable.wilshere)   ;
          }else if(child=="Alexis Sanchez")
          {
            img.setImageResource(R.drawable.sanchez)    ;
          }else if(child=="Aaron Ramsey")
          {
            img.setImageResource(R.drawable.ramsey) ;
          }else if(child=="Mesut Ozil")
          {
            img.setImageResource(R.drawable.ozil)   ;
          }
        }
    
        return convertView;
      }
    
      //GET NUMBER OF PLAYERS
      @Override
      public int getChildrenCount(int groupPosw) {
        // TODO Auto-generated method stub
        return team.get(groupPosw).players.size();
      }
    
      //GET TEAM
      @Override
      public Object getGroup(int groupPos) {
        // TODO Auto-generated method stub
        return team.get(groupPos);
      }
    
      //GET NUMBER OF TEAMS
      @Override
      public int getGroupCount() {
        // TODO Auto-generated method stub
        return team.size();
      }
    
      //GET TEAM ID
      @Override
      public long getGroupId(int arg0) {
        // TODO Auto-generated method stub
        return 0;
      }
    
      //GET TEAM ROW
      @Override
      public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
    
        //ONLY INFLATE XML TEAM ROW MODEL IF ITS NOT PRESENT,OTHERWISE REUSE IT
            if(convertView == null)
            {
              convertView=inflater.inflate(R.layout.teams, null);
            }
    
            //GET GROUP/TEAM ITEM
            Team t=(Team) getGroup(groupPosition);
    
            //SET GROUP NAME
            TextView nameTv=(TextView) convertView.findViewById(R.id.textView1);
            ImageView img=(ImageView) convertView.findViewById(R.id.imageView1);
    
            String name=t.Name;
            nameTv.setText(name);
    
            //ASSIGN TEAM IMAGES ACCORDING TO TEAM NAME
    
            if(name=="Man Utd")
            {
              img.setImageResource(R.drawable.manutd);
            }else if(name=="Chelsea")
            {
              img.setImageResource(R.drawable.chelsea);
            }else if(name=="Arsenal")
            {
              img.setImageResource(R.drawable.arsenal);
            }
    
            //SET TEAM ROW BACKGROUND COLOR
            convertView.setBackgroundColor(Color.LTGRAY);
    
        return convertView;
      }
    
      @Override
      public boolean hasStableIds() {
        // TODO Auto-generated method stub
        return false;
      }
    
      @Override
      public boolean isChildSelectable(int arg0, int arg1) {
        // TODO Auto-generated method stub
        return true;
      }
    
    }

    4. MainActivity.java

    So this is our main activity. It derives from android.app.Activity.

    Here are it’s major responsibilities:

    No. Responsibility
    1. Allow itself to become an android activity component by deriving from android.app.activity.
    2. Listen to activity creation callbacks by overrding the onCreate() method.
    3. Invoke the onCreate() method of the parent Activity class and tell it of a Bundle we’ve received.
    4. Inflate the activity_main.xml into a View object and set it as the content view of this activity.
    5. Search for our ExpandableListView by it’s id from our layouts.
    6. Create an java and fill it with some data. This acts as our data source.
    7. Instantiate our CustomAdapter class and pass it that data source as well as our Activity’s context.
    8. Set that adapter into our ExpandableListView.
    9. Listen to ExpandableListView children’ click events and show a Toast message.
    package com.tutorials.expandable_view;
    
    import java.util.ArrayList;
    
    import android.os.Bundle;
    import android.app.Activity;
    import android.view.Menu;
    import android.view.View;
    import android.widget.ExpandableListView;
    import android.widget.ExpandableListView.OnChildClickListener;
    import android.widget.Toast;
    
    public class MainActivity extends Activity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            //THE EXPANDABLE
            ExpandableListView elv=(ExpandableListView) findViewById(R.id.expandableListView1);
    
            final ArrayList<Team> team=getData();
    
            //CREATE AND BIND TO ADAPTER
            CustomAdapter adapter=new CustomAdapter(this, team);
            elv.setAdapter(adapter);
    
            //SET ONCLICK LISTENER
            elv.setOnChildClickListener(new OnChildClickListener() {
    
          @Override
          public boolean onChildClick(ExpandableListView parent, View v, int groupPos,
              int childPos, long id) {
    
                       Toast.makeText(getApplicationContext(), team.get(groupPos).players.get(childPos), Toast.LENGTH_SHORT).show();
    
            return false;
          }
        });
        }
    
        //ADD AND GET DATA
    
        private ArrayList<Team> getData()
        {
    
            Team t1=new Team("Man Utd");
            t1.players.add("Wayne Rooney");
            t1.players.add("Van Persie");
            t1.players.add("Ander Herera");
            t1.players.add("Juan Mata");
    
            Team t2=new Team("Arsenal");
            t2.players.add("Aaron Ramsey");
            t2.players.add("Mesut Ozil");
            t2.players.add("Jack Wilshere");
            t2.players.add("Alexis Sanchez");
    
            Team t3=new Team("Chelsea");
            t3.players.add("John Terry");
            t3.players.add("Eden Hazard");
            t3.players.add("Diego Costa");
            t3.players.add("Oscar");
    
            ArrayList<Team> allTeams=new ArrayList<Team>();
            allTeams.add(t1);
            allTeams.add(t2);
            allTeams.add(t3);
    
            return allTeams;
        }
    
    }

    Our Manifest

    This is our application manifest. Note that the minSDKVersion and targetSDKVersion aren’t strict, you can set them much lower or higher.

    <?xml version="1.0" encoding="utf-8"?>
    <manifest 
        package="com.tutorials.expandable_view"
        android_versionCode="1"
        android_versionName="1.0" >
    
        <uses-sdk
            android_minSdkVersion="19"
            android_targetSdkVersion="19" />
    
        <application
            android_allowBackup="true"
            android_icon="@drawable/ic_launcher"
            android_label="@string/app_name"
            android_theme="@style/AppTheme" >
            <activity
                android_name="com.tutorials.expandable_view.MainActivity"
                android_label="@string/app_name" >
                <intent-filter>
                    <action android_name="android.intent.action.MAIN" />
    
                    <category android_name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>

    How To Run

    1. This project was created by Eclipse.
    2. Therefore just copy the code and use in your project in android studio, it’s still android anyway and expandableListview is the same regardless of the IDE. So copy paste the code to your android studio project.

    Resources

    No. Resource Direct Links
    1. YouTube YouTube Channel



Share an Example

Share an Example

Browse
What is the capital of Egypt? ( Cairo )