Wednesday, January 4, 2017

Easy Tutorial Android Expandable RecyclerView

Today i going to share a awesome tutorial using recyclerview. As usual, you may use ListView for creating a collapse and expand view, right?

We using listview with reason that listview have a view called ExpandableListView, so we just set the data through ExapandableListView.


But in several case, your application required a Recyclerview (I don't know what it is) instead of Listview.

Indeed, create a expandable view using recyclerview is more difficult that using ExpandableListview. You have to create all materials or view not just set the data.

But don't worry, i have spent several hours just to create simple expandable view using recyclerview, with hope you will easy to understand the steps.

PREPARATION


Compile the following libraries :

compile 'com.android.support:design:23.2.0'
compile 'com.android.support:cardview-v7:23.2.0'
compile 'com.android.support:recyclerview-v7:23.2.0'

After that, download LIB MODULE EXPANDABLE , extract and then place in your main package. Confuse? Take a look at Figure 1 :

Figure 1

Place the LIB MODULE EXPANDABLE look like figure 1.

IMPLEMENTATION


Create new 3 xml layouts :
  1. activity_main.xml
  2. item_list_parent.xml
  3. item_list_child.xml

At Figure 1, there are several packages that have some java classes.

Package models
  1. BiodataChildModel.java
  2. BiodataParentModel.java

Package expandables
  1. BiodataChildViewHolder.java
  2. BiodataParentViewHolder.java
  3. BiodataExpandable.java
And last, definitely MainActivity.java.

First, modify the layouts that we've prepared.

activity_main.xml. Paste the following code :

<?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:id="@+id/activity_main"
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"
android:orientation="vertical"
tools:context="com.androidbie.recyclerviewexapandable.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_marginLeft="@dimen/value_20"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/lbl_people_name"/>
<TextView
android:layout_marginLeft="@dimen/value_20"
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:text="@string/lbl_people_age"/>
</LinearLayout>
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_marginTop="@dimen/value_20"
android:layout_width="match_parent"
android:layout_height="match_parent"></android.support.v7.widget.RecyclerView>
</LinearLayout>
item_list_child.xml. Paste the following code :

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:padding="@dimen/value_20"
android:layout_height="wrap_content">
<TextView
android:id="@+id/text_view_status"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/lbl_status"/>
<TextView
android:id="@+id/text_view_desc"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/lbl_description"/>
</LinearLayout>
item_list_parent.xml. Paste the following code :

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:id="@+id/ll_item"
android:paddingRight="@dimen/value_20"
android:paddingLeft="@dimen/value_20"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_weight="1"
android:id="@+id/textview_name"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center|left"
android:text="@string/lbl_name"/>
<TextView
android:layout_weight="1"
android:id="@+id/textview_age"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/lbl_age"/>
<ImageView
android:id="@+id/image_view_collapse"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_content_add"/>
</LinearLayout>
</android.support.v7.widget.CardView>
Second, we modify the code of all the java classes inside the package models. Why this package is first? Because this classes will use in next next java classes.

1. Package MODELS

Open BiodataChildModel.java. This class store all the data that will show on expand view. Paste the following code :

package com.androidbie.recyclerviewexapandable.models;
/**
* Created by putuguna on 04/01/17.
*/
public class BiodataChildModel {
private String status;
private String descriptions;
public BiodataChildModel(String status, String descriptions) {
this.status = status;
this.descriptions = descriptions;
}
public BiodataChildModel() {
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getDescriptions() {
return descriptions;
}
public void setDescriptions(String descriptions) {
this.descriptions = descriptions;
}
}
Then modify class BiodataParentModel.java. This class contains data from class BiodataChildModel and set as a list.

Because this class as the parent, you have to extends ParentListItem. After you do extends, you have to implements its methods. Take a look at the following code  :

package com.androidbie.recyclerviewexapandable.models;
import com.androidbie.recyclerviewexapandable.libmoduleExpandable.Model.ParentListItem;
import java.util.List;
/**
* Created by putuguna on 04/01/17.
*/
public class BiodataParentModel implements ParentListItem {
private String name;
private String age;
private List<BiodataChildModel> mListChild;
public BiodataParentModel(String name, String age, List<BiodataChildModel> mListChild) {
this.name = name;
this.age = age;
this.mListChild = mListChild;
}
public BiodataParentModel() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
public List<BiodataChildModel> getmListChild() {
return mListChild;
}
public void setmListChild(List<BiodataChildModel> mListChild) {
this.mListChild = mListChild;
}
@Override
public List<?> getChildItemList() {
return mListChild;
}
@Override
public boolean isInitiallyExpanded() {
return false;
}
}
Attention :
Make sure you have returned mListChild in method getChildItemList()

2. Package EXPANDABLES

Open class BiodataChildViewHolder.java. Paste the following code :


package com.androidbie.recyclerviewexapandable.expandables;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.androidbie.recyclerviewexapandable.R;
import com.androidbie.recyclerviewexapandable.libmoduleExpandable.ViewHolder.ChildViewHolder;
import com.androidbie.recyclerviewexapandable.models.BiodataChildModel;
/**
* Created by putuguna on 04/01/17.
*/
public class BiodataChildViewHolder extends ChildViewHolder {
private TextView tvStatus;
private TextView tvDesc;
public BiodataChildViewHolder(View itemView) {
super(itemView);
tvDesc = (TextView) itemView.findViewById(R.id.text_view_desc);
tvStatus = (TextView) itemView.findViewById(R.id.text_view_status);
}
public void bind(BiodataChildModel biodataChildModel){
Log.d("TAG", "appears " + getAdapterPosition());
tvStatus.setText(biodataChildModel.getStatus());
tvDesc.setText(biodataChildModel.getDescriptions());
}
}
Open class BiodataParentViewHolder.java. Paste the following code :

package com.androidbie.recyclerviewexapandable.expandables;
import android.graphics.Color;
import android.os.Build;
import android.view.View;
import android.view.animation.RotateAnimation;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.androidbie.recyclerviewexapandable.R;
import com.androidbie.recyclerviewexapandable.libmoduleExpandable.ViewHolder.ParentViewHolder;
import com.androidbie.recyclerviewexapandable.models.BiodataParentModel;
/**
* Created by putuguna on 04/01/17.
*/
public class BiodataParentViewHolder extends ParentViewHolder {
private static final float INITIAL_POSITION = 0.0f;
private static final float ROTATED_POSITION = 180f;
private TextView tvName;
private TextView tvAge;
private ImageView ivCollapse;
private LinearLayout llItem;
public BiodataParentViewHolder(View itemView) {
super(itemView);
tvName = (TextView) itemView.findViewById(R.id.textview_name);
tvAge = (TextView) itemView.findViewById(R.id.textview_age);
ivCollapse = (ImageView) itemView.findViewById(R.id.image_view_collapse);
llItem = (LinearLayout) itemView.findViewById(R.id.ll_item);
}
public void bind(BiodataParentModel biodataHead){
tvName.setText(biodataHead.getName());
tvAge.setText(biodataHead.getAge());
int position = getAdapterPosition();
if(position%2 == 0) {
llItem.setBackgroundColor(Color.parseColor("#ffffff"));
} else {
llItem.setBackgroundColor(Color.parseColor("#f1f1f1"));
}
}
@Override
public void setExpanded(boolean expanded) {
super.setExpanded(expanded);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
if (expanded) {
ivCollapse.setImageResource(R.drawable.ic_content_remove);
} else {
ivCollapse.setImageResource(R.drawable.ic_content_add);
}
}
}
@Override
public void onExpansionToggled(boolean expanded) {
super.onExpansionToggled(expanded);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
RotateAnimation rotateAnimation;
if (expanded) { // rotate clockwise
rotateAnimation = new RotateAnimation(ROTATED_POSITION,
INITIAL_POSITION,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
} else { // rotate counterclockwise
rotateAnimation = new RotateAnimation(-1 * ROTATED_POSITION,
INITIAL_POSITION,
RotateAnimation.RELATIVE_TO_SELF, 0.5f,
RotateAnimation.RELATIVE_TO_SELF, 0.5f);
}
rotateAnimation.setDuration(200);
rotateAnimation.setFillAfter(true);
ivCollapse.startAnimation(rotateAnimation);
}
}
}
In code above there are method :
  1. setExpanded(boolean expanded) 
  2. onExpansionToggled(boolean expanded) . 
Those method used to create an animation of the imageview (icon + and -) when the view is expand or collapse. You can see on the video demo above.

Open class BiodataExpandable.java. Paste the following code :

package com.androidbie.recyclerviewexapandable.expandables;
import android.content.Context;
import android.support.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.androidbie.recyclerviewexapandable.R;
import com.androidbie.recyclerviewexapandable.libmoduleExpandable.Adapter.ExpandableRecyclerAdapter;
import com.androidbie.recyclerviewexapandable.libmoduleExpandable.Model.ParentListItem;
import com.androidbie.recyclerviewexapandable.models.BiodataChildModel;
import com.androidbie.recyclerviewexapandable.models.BiodataParentModel;
import java.util.List;
/**
* Created by putuguna on 04/01/17.
*/
public class BiodataExpandable extends ExpandableRecyclerAdapter<BiodataParentViewHolder, BiodataChildViewHolder> {
private LayoutInflater mLayoutInflater;
private Context mContext;
public BiodataExpandable(@NonNull List<? extends ParentListItem> parentItemList, Context mContext) {
super(parentItemList);
this.mLayoutInflater = LayoutInflater.from(mContext);
this.mContext = mContext;
}
@Override
public BiodataParentViewHolder onCreateParentViewHolder(ViewGroup parentViewGroup) {
View view = mLayoutInflater.inflate(R.layout.item_list_parent, parentViewGroup, false);
return new BiodataParentViewHolder(view);
}
@Override
public BiodataChildViewHolder onCreateChildViewHolder(ViewGroup childViewGroup) {
View view = mLayoutInflater.inflate(R.layout.item_list_child, childViewGroup, false);
return new BiodataChildViewHolder(view);
}
@Override
public void onBindParentViewHolder(BiodataParentViewHolder parentViewHolder, int position, ParentListItem parentListItem) {
BiodataParentModel head = (BiodataParentModel) parentListItem;
parentViewHolder.bind(head);
}
@Override
public void onBindChildViewHolder(BiodataChildViewHolder childViewHolder, int position, Object childListItem) {
BiodataChildModel child = (BiodataChildModel) childListItem;
childViewHolder.bind(child);
}
}
All the class that used to create expandable has done. Time to input the data and set adapter in your MainActivity.java. Paste the following code :

package com.androidbie.recyclerviewexapandable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import com.androidbie.recyclerviewexapandable.expandables.BiodataExpandable;
import com.androidbie.recyclerviewexapandable.models.BiodataChildModel;
import com.androidbie.recyclerviewexapandable.models.BiodataParentModel;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private RecyclerView rvBiodata;
private BiodataExpandable mBiodataExapandable;
List<BiodataParentModel> listModelBiodata = new ArrayList<>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
rvBiodata = (RecyclerView) findViewById(R.id.recyclerview);
setData();
rvBiodata.setLayoutManager(new LinearLayoutManager(this));
mBiodataExapandable = new BiodataExpandable(listModelBiodata, this);
rvBiodata.setItemAnimator(new DefaultItemAnimator());
rvBiodata.setAdapter(mBiodataExapandable);
}
private void setData(){
List<BiodataChildModel> mChildBiodata1 = new ArrayList<>();
mChildBiodata1.add(new BiodataChildModel("Single", "I am a free man!"));
List<BiodataChildModel> mChildBiodata2 = new ArrayList<>();
mChildBiodata2.add(new BiodataChildModel("Married", "I am a married man!"));
List<BiodataChildModel> mChildBiodata3 = new ArrayList<>();
mChildBiodata3.add(new BiodataChildModel("Young", "I am a young man!"));
List<BiodataChildModel> mChildBiodata4 = new ArrayList<>();
mChildBiodata4.add(new BiodataChildModel("Married", "I am a married man!"));
List<BiodataChildModel> mChildBiodata5 = new ArrayList<>();
mChildBiodata5.add(new BiodataChildModel("Semelekete", "I am a semelekete man!"));
BiodataParentModel mHeadBiodata1 = new BiodataParentModel();
mHeadBiodata1.setAge("10");
mHeadBiodata1.setName("Komak");
mHeadBiodata1.setmListChild(mChildBiodata1);
BiodataParentModel mHeadBiodata2 = new BiodataParentModel();
mHeadBiodata2.setAge("20");
mHeadBiodata2.setName("Kacang");
mHeadBiodata2.setmListChild(mChildBiodata2);
BiodataParentModel mHeadBiodata3 = new BiodataParentModel();
mHeadBiodata3.setAge("15");
mHeadBiodata3.setName("Kare");
mHeadBiodata3.setmListChild(mChildBiodata3);
BiodataParentModel mHeadBiodata4 = new BiodataParentModel();
mHeadBiodata4.setAge("24");
mHeadBiodata4.setName("Kedelai");
mHeadBiodata4.setmListChild(mChildBiodata4);
BiodataParentModel mHeadBiodata5 = new BiodataParentModel();
mHeadBiodata5.setAge("32");
mHeadBiodata5.setName("Rozan");
mHeadBiodata5.setmListChild(mChildBiodata5);
listModelBiodata.add(mHeadBiodata1);
listModelBiodata.add(mHeadBiodata2);
listModelBiodata.add(mHeadBiodata3);
listModelBiodata.add(mHeadBiodata4);
listModelBiodata.add(mHeadBiodata5);
}
}
Done!!! Run your project, hope the project is running well :D. Thank you.

Download the project here

Related Posts

1 komentar so far

After 3 days of trying to find a simple, customizable expanding recyclerview (so I could easily add a click listener to each child and properly index it), this was simply the cleanest and most concise example available. libmoduleExpandable was a gold nugget in a bed of rocks!

Thank you!


EmoticonEmoticon

:)
:(
hihi
:-)
:D
=D
:-d
;(
;-(
@-)
:o
:>)
(o)
:p
:-?
(p)
:-s
8-)
:-t
:-b
b-(
(y)
x-)
(h)