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 xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    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 xmlns:android="http://schemas.android.com/apk/res/android"
    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 xmlns:android="http://schemas.android.com/apk/res/android"
    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 xmlns:android="http://schemas.android.com/apk/res/android"
    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

How do You Feel after reading this?

According to scientists, we humans have 8 primary innate emotions: joy, acceptance, fear, surprise, sadness, disgust, anger, and anticipation. Feel free to tell us how you feel about this article using these emotes or via the comment section. This feedback helps us gauge our progress.

Help me Grow.

I set myself some growth ambitions I desire to achieve by this year's end regarding this website and my youtube channel. Am halfway. Help me reach them by:




Recommendations


What do You Think

Dear readers drop us your comments below. We are building a community of students and learners. Start by dropping us your suggestions below. What tutorials do you want us to do for example? Where can we improve? What are some awesome resources out there? Do you have any code you want to share with us?
By the way that example or snippet you have lying in your computer can really help beginner programmers. We can share it here with other students.

Previous Post Next Post