In this post we will see how we can create Android Expandable listview and get name of the selected child. We will create a simple Year and Movies LinkedHaspMap object and use it to fill our Android Exapandable listview. So let’s begin.
Android Expandable Listview Source code download.
First, please download following icons from IconFinder:
Copy the icons as shown in the above image.
Create three layout files as following:
res>layout>mylist.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:orientation="vertical"> <ExpandableListView android:id="@+id/myExpandableList" android:layout_width="match_parent" android:layout_height="match_parent" android:divider="#000" android:dividerHeight="1dp" android:groupIndicator="@drawable/listselection"/> </LinearLayout>
This will be our layout file. Create a new drawable file as below:
res>drawable>listselection.xml:
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/minus" android:state_empty="false" /> <item android:drawable="@drawable/minus" android:state_expanded="true" /> <item android:drawable="@drawable/plus" /> </selector>
This will be our List indicator for whether its elements our expanded or collapsed.
Now we will create the Header file and the child file. Header file will be used for showing the expandable listview’s heading and child file will be used to show its data. We will use years (2019,2018) as our header and some of the best movies released in the following years (Parasite, Deadpool 2, Joker) as its child data.
res>layout>listparent.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="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/txtHeader" android:layout_width="wrap_content" android:layout_height="wrap_content" android:padding="10dp" android:textSize="25sp" android:textColor="#000" /> </LinearLayout>
res>layout>listchilds.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/txtChild" android:padding="20dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="#4E4E4E" android:textSize="20sp"/> </LinearLayout>
Now, let’s create a class files to make our Expandable list view work.
Movies.java:
package com.app.expandablelist; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; public class Movies { public static LinkedHashMap<String, List<String>> getMovies() { LinkedHashMap<String, List<String>> myData = new LinkedHashMap<String,List<String>>(); List<String> movies2019 = new ArrayList<String>(); movies2019.add("Parasite"); movies2019.add("Avengers Endgame"); movies2019.add("Joker"); movies2019.add("Ford vs Ferrari"); List<String> movies2018 = new ArrayList<String>(); movies2018.add("Black Panther"); movies2018.add("A Quiet Place"); movies2018.add("Incredibles 2"); movies2018.add("Deadpool 2"); List<String> movies2017 = new ArrayList<String>(); movies2017.add("Get Out"); movies2017.add("Dunkrik"); movies2017.add("Logan"); movies2017.add("Baby Driver"); myData.put("2017", movies2017); myData.put("2018", movies2018); myData.put("2019", movies2019); return myData; } }
This will return a LinkedHashMap<String,List<String>> object containing movies with its year released.
listadapter.java:
package com.app.expandablelist; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseExpandableListAdapter; import android.widget.TextView; import java.util.LinkedHashMap; import java.util.List; public class listadapter extends BaseExpandableListAdapter { private Context context; private List<String> year; private LinkedHashMap<String, List<String>> movies; public listadapter(Context context, List<String> year, LinkedHashMap<String, List<String>> movieName) { this.context = context; this.year = year; this.movies = movieName; } @Override public Object getChild(int listPosition, int expandedListPosition) { return this.movies.get(this.year.get(listPosition)) .get(expandedListPosition); } @Override public long getChildId(int listPosition, int expandedListPosition) { return expandedListPosition; } @Override public View getChildView(int listPosition, final int expandedListPosition, boolean isLastChild, View convertView, ViewGroup parent) { final String expandedListText = (String) getChild(listPosition, expandedListPosition); if (convertView == null) { LayoutInflater layoutInflater = (LayoutInflater) this.context .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = layoutInflater.inflate(R.layout.listchilds, null); } TextView expandedListTextView = convertView.findViewById(R.id.txtChild); expandedListTextView.setText(expandedListText); return convertView; } @Override public int getChildrenCount(int listPosition) { return this.movies.get(this.year.get(listPosition)) .size(); } @Override public Object getGroup(int listPosition) { return this.year.get(listPosition); } @Override public int getGroupCount() { return this.year.size(); } @Override public long getGroupId(int listPosition) { return listPosition; } @Override public View getGroupView(int listPosition, boolean isExpanded, View convertView, ViewGroup parent) { String listTitle = (String) getGroup(listPosition); if (convertView == null) { LayoutInflater layoutInflater = (LayoutInflater) this.context. getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = layoutInflater.inflate(R.layout.listparent, null); } TextView listTitleTextView = convertView.findViewById(R.id.txtHeader); listTitleTextView.setText(listTitle); return convertView; } @Override public boolean hasStableIds() { return false; } @Override public boolean isChildSelectable(int listPosition, int expandedListPosition) { return true; } }
This will be our Listview adapter. We will pass List<String> (years) and LinkedHashMap<String, List<String>> (years and movies).
MyList.java:
package com.app.expandablelist; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; import android.util.DisplayMetrics; import android.view.View; import android.widget.ExpandableListView; import android.widget.Toast; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; public class MyList extends AppCompatActivity { ExpandableListView myExpandableList; listadapter expandableListAdapter; List<String> moviesTitle; LinkedHashMap<String, List<String>> moviesDetail; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.mylist); myExpandableList = findViewById(R.id.myExpandableList); DisplayMetrics metrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(metrics); int width = metrics.widthPixels; myExpandableList.setIndicatorBounds(width - GetPixelFromDips(50), width - GetPixelFromDips(5)); moviesDetail = Movies.getMovies(); moviesTitle = new ArrayList<String>(moviesDetail.keySet()); expandableListAdapter = new listadapter(this, moviesTitle, moviesDetail); myExpandableList.setAdapter(expandableListAdapter); myExpandableList.setOnGroupExpandListener(new ExpandableListView.OnGroupExpandListener() { @Override public void onGroupExpand(int groupPosition) { Toast.makeText(getApplicationContext(), moviesTitle.get(groupPosition)+" expanded.", Toast.LENGTH_SHORT).show(); } }); myExpandableList.setOnGroupCollapseListener(new ExpandableListView.OnGroupCollapseListener() { @Override public void onGroupCollapse(int groupPosition) { Toast.makeText(getApplicationContext(), moviesTitle.get(groupPosition) + " collapsed.", Toast.LENGTH_SHORT).show(); } }); myExpandableList.setOnChildClickListener(new ExpandableListView.OnChildClickListener() { @Override public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) { Toast.makeText( getApplicationContext(), moviesDetail.get( moviesTitle.get(groupPosition)).get( childPosition), Toast.LENGTH_SHORT ).show(); return false; } }); } public int GetPixelFromDips(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); } }
This class will be our Activity class.
Create a new string object in strings.xml for name of our activity:
res > values > strings.xml:
<resources> <string name="app_name">ExpandableList</string> <string name="action_settings">Settings</string> <string name="movies_header">Movies by Year</string> </resources>
res > values > colors.xml:
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="colorPrimary">#3949AB</color> <color name="colorPrimaryDark">#1F2966</color> <color name="colorAccent">#000</color> </resources>
Edit your AndroidManifest.xml as below:
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.app.expandablelist"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MyList" android:label="@string/movies_header" android:theme="@style/AppTheme"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
Download source code using the link below:
Android Expandable Listview Source code download.
Also see:
Create Android Listview which scrolls Horizontally and Vertically.
Android Listview binding from MySQL Database table
Android Listview binding from SQLite database