Expandable Recyclerview Android Example [Updated]

Steps To Create Expandable Recyclerview

  1. Adding Dependencies
  2. Prepare data for the recyclerview
  3. Design Header & child items layout for expandable recyclerview
  4. set data into expandable recyclerview

1. Adding dependencies

In this example, I am using Mindorks Placeholder library to create an Expandable Recyclerview for android.

implementation 'com.mindorks:placeholderview:0.7.1'
implementation "androidx.cardview:cardview:1.0.0"
implementation "androidx.recyclerview:recyclerview:1.1.0"
//Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'
//Glide
implementation 'com.github.bumptech.glide:glide:4.6.1'

2. Prepare data for the recyclerview

Next, step is to prepare data for the expandable recyclerview.

[{
"category": "Latest",
"imageUrl": "http://velmm.com/images/bottom_navigationview/coco.jpg",
"name": "Coco",
"desc": "Coco is a 2017 American 3D computer-animated musical fantasy adventure film produced by Pixar"
},
{
"category": "Latest",
"imageUrl": "http://velmm.com/images/bottom_navigationview/terminator_2.jpg",
"name": "Terminator 2: Judgment Day 3D",
"desc": "Similar to Cameron's Titanic 3D, Lightstorm Entertainment oversaw the work on the 3D version of Terminator 2, which took nearly a year to finish."
},
{
"category": "Latest",
"imageUrl": "http://velmm.com/images/bottom_navigationview/dunkirk.jpg",
"name": "Dunkirk",
"desc": "Dunkirk is a 2017 war film written, directed, and co-produced by Christopher Nolan that depicts the Dunkirk evacuation of World War II. "
},
{
"category": "Favorites",
"imageUrl": "http://velmm.com/images/bottom_navigationview/the_salesman.jpg",
"name": "The Salesman",
"desc": "The Salesman is a 2016 drama film written and directed by Asghar Farhadi and starring Taraneh Alidoosti and Shahab Hosseini. "
},
{
"category": "Favorites",
"imageUrl": "http://velmm.com/images/bottom_navigationview/lion.png",
"name": "Lion",
"desc": "Lion is a 2016 Australian biographical drama film directed by Garth Davis (in his feature debut) and written by Luke Davies, based on the non-fiction book A Long Way Home by Saroo Brierley."
},
{
"category": "High Rated",
"imageUrl": "http://velmm.com/images/bottom_navigationview/star_war.jpg",
"name": "Star Wars: The Last Jedi",
"desc": "Star Wars: The Last Jedi (also known as Star Wars: Episode VIII – The Last Jedi) is a 2017 American epic space opera film written and directed by Rian Johnson."
},
{
"category": "High Rated",
"imageUrl": "http://velmm.com/images/bottom_navigationview/thor_ragnarok.jpg",
"name": "Thor: Ragnarok",
"desc": "Thor: Ragnarok is a 2017 American superhero film based on the Marvel Comics character Thor, produced by Marvel Studios and distributed by Walt Disney Studios Motion Pictures."
},
{
"category": "High Rated",
"imageUrl": "http://velmm.com/images/bottom_navigationview/blade_runner_2049.jpg",
"name": "Blade Runner 2049",
"desc": "Blade Runner 2049 is a 2017 American science fiction film directed by Denis Villeneuve and written by Hampton Fancher and Michael Green. "
},
{
"category": "High Rated",
"imageUrl": "http://velmm.com/images/bottom_navigationview/borg_mcenroe.jpg",
"name": "Borg McEnroe",
"desc": "Borg McEnroe also known as Borg vs McEnroe, is a 2017 internationally co-produced multi-language biographical sports drama film focusing on the famous rivalry between famous tennis players "
},
{
"category": "High Rated",
"imageUrl": "http://velmm.com/images/bottom_navigationview/wonder.jpg",
"name": "Wonder",
"desc": "Wonder is a 2017 American drama film directed by Stephen Chbosky and written by Jack Thorne , Steve Conrad and Stephen Chbosky based on the 2012 novel of the same name by R.J. Palacio."
}
]
public class Movie {

@SerializedName("name")
private String name;
@SerializedName("desc")
private String desc;
@SerializedName("imageUrl")
private String imageUrl;
@SerializedName("category")
private String categoty;

public Movie(String name, String desc, String imageUrl, String categoty) {
this.name = name;
this.desc = desc;
this.imageUrl = imageUrl;
this.categoty = categoty;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getDesc() {
return desc;
}

public void setDesc(String desc) {
this.desc = desc;
}

public String getImageUrl() {
return imageUrl;
}

public void setImageUrl(String imageUrl) {
this.imageUrl = imageUrl;
}

public String getCategoty() {
return categoty;
}

public void setCategoty(String categoty) {
this.categoty = categoty;
}

@Override
public String toString() {
return "Movie{" +
"name='" + name + '\'' +
", desc='" + desc + '\'' +
", imageUrl='" + imageUrl + '\'' +
", categoty='" + categoty + '\'' +
'}';
}
}
public interface ApiInterface {
@GET("movielist.json")
Call<List<Movie>> getAllMovies();
}

3. Design Header & child items for expandable recyclerview

In this step, I am creating layouts for the expandable view header and child layouts.

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_margin="5dp"
android:elevation="5dp"
app:cardBackgroundColor="@color/colorPrimaryDark"
app:cardCornerRadius="8dp">

<TextView
android:id="@+id/header_text"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center_vertical"
android:gravity="center_vertical"
android:padding="10dp"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
android:textColor="@android:color/white"
android:textStyle="bold"
tools:text="@tools:sample/full_names" />

</androidx.cardview.widget.CardView>
header layout view
@Parent
@SingleTop
@Layout(R.layout.header_layout)
public class HeaderView {

private static String TAG = "HeaderView";

@View(R.id.header_text)
TextView headerText;

private Context mContext;
private String mHeaderText;

public HeaderView(Context context,String headerText) {
this.mContext = context;
this.mHeaderText = headerText;
}

@Resolve
private void onResolve(){
headerText.setText(mHeaderText);
}

@Expand
private void onExpand(){
Toast.makeText(mContext, "onExpand "+mHeaderText, Toast.LENGTH_SHORT).show();
}

@Collapse
private void onCollapse(){
Toast.makeText(mContext, "onCollapse "+mHeaderText, Toast.LENGTH_SHORT).show();
}
}
  • A class is defined as a parent item view through @Parent class annotation.
  • A parent item view on expand will collapse other parent item views when annotated with @SingleTop. If not provided with this annotation then all the parent item will remain in their expanded state irrespective of whether other parent expand or collapse.
  • A parent gets callback when it is expanded or collapsed through @Expand and @Collapse annotations respectively. They can be used to handle state changed. For Example: we can change the indicator icon.
  • The views defined in the layout provided by @Layout can be referenced in the item view class using @View annotations on the global variable.
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/card_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:elevation="5dp"
app:cardBackgroundColor="@color/colorPrimary"
android:layout_marginLeft="20dp"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:layout_marginRight="5dp"
card_view:cardCornerRadius="10dp">


<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">

<ImageView
android:id="@+id/child_image"
android:layout_width="70dp"
android:layout_height="70dp"
android:scaleType="centerCrop"
tools:src="@tools:sample/backgrounds/scenic"
card_view:layout_constraintTop_toTopOf="parent"
card_view:layout_constraintStart_toStartOf="parent"

/>

<TextView
android:id="@+id/child_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentEnd="true"
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="@android:color/white"
android:textStyle="bold"
card_view:layout_constraintBottom_toBottomOf="@+id/child_image"
card_view:layout_constraintEnd_toEndOf="parent"
card_view:layout_constraintStart_toEndOf="@+id/child_image"
card_view:layout_constraintTop_toTopOf="@+id/child_image"
tools:text="@tools:sample/full_names" />

</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
child layout design
@Layout(R.layout.child_layout)
public class ChildView {
private static String TAG ="ChildView";

@View(R.id.child_name)
TextView textViewChild;


@View(R.id.child_image)
ImageView childImage;

private Context mContext;
private Movie movie;

public ChildView(Context mContext, Movie movie) {
this.mContext = mContext;
this.movie = movie;
}

@Resolve
private void onResolve(){
textViewChild.setText(movie.getName());
Glide.with(mContext).load(movie.getImageUrl()).into(childImage);
textViewChild.setOnClickListener(new android.view.View.OnClickListener() {
@Override
public void onClick(android.view.View v) {
Toast.makeText(mContext, movie.getName(), Toast.LENGTH_SHORT).show();
}
});
}
}

4.set data into expandable recyclerview

Already, we have done the setup for data and header , child view. Now. Its a time to setup expandable recyclerview.

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
tools:context="com.example.velmurugan.expandablerecyclerviewexample.MainActivity">

<com.mindorks.placeholderview.ExpandablePlaceHolderView
android:id="@+id/expandablePlaceHolder"
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.mindorks.placeholderview.ExpandablePlaceHolderView>

</LinearLayout>
expandablePlaceHolderView.addView(new HeaderView(this, "header"));
expandablePlaceHolderView.addView(new ChildView(this, movie));
private void getHeaderAndChild(List<Movie> movieList){

for (Movie movie : movieList ){
List<Movie> movieList1 = categoryMap.get(movie.getCategoty());
if(movieList1 == null){
movieList1 = new ArrayList<>();
}
movieList1.add(movie);
categoryMap.put(movie.getCategoty(),movieList1);
}

Log.d("Map",categoryMap.toString());
Iterator it = categoryMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
Log.d("Key", pair.getKey().toString());
expandablePlaceHolderView.addView(new HeaderView(this, pair.getKey().toString()));
List<Movie> movieList1 = (List<Movie>) pair.getValue();
for (Movie movie : movieList1){
expandablePlaceHolderView.addView(new ChildView(this, movie));
}
it.remove();
}
}
try {
expandableView.expand(parentItemView);
} catch (Resources.NotFoundException e) {
e.printStackTrace();
}

or

try {
expandableView.expand(2);
} catch (Resources.NotFoundException e) {
e.printStackTrace();
}
try {
expandableView.collapse(parentItemView);
} catch (Resources.NotFoundException e) {
e.printStackTrace();
}

or

try {
expandableView.collapse(2);
} catch (Resources.NotFoundException e) {
e.printStackTrace();
}
expandableView.collapseAll();
expandable recyclerview screenshot

Conclusion

Thanks for reading this post. In this example, I am using PlaceHolder Library. There are lot of library available for the same example. Please try this and let me know your feedback in comments section.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Velmurugan Murugesan

Velmurugan Murugesan

434 Followers

Lead Android Engineer @htcindia | @github contributor | Blog writer @howtodoandroid | Quick Learner