Android Nested RecyclerViews with expandable list
The following is an example for creating nested RecyclerViews in Android. A list RecyclerViews are items of a parent RecyclerView. The parent RecyclerView with vertical scrolling containing a list of RecyclerViews that are also with vertical scrolling and each of them can be expanded or collapsed.
Dependencies used:
compile 'com.android.support:recyclerview-v7:25.1.0' compile 'com.android.support:cardview-v7:25.1.0' compile 'com.jakewharton:butterknife:7.0.1'
Model classes:
public class Child {
String child_name;
public Child() {}
public String getChild_name() {
return child_name;
}
public void setChild_name(String child_name) {
this.child_name = child_name;
}
}
import java.util.ArrayList;
public class ParentChild {
ArrayList child;
public ParentChild() {}
public ArrayList getChild() {
return child;
}
public void setChild(ArrayList child) {
this.child = child;
}
}
Adapter classes:
import android.os.Handler; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.TextView; import com.example.nestedrecyclerview.R; import com.example.nestedrecyclerview.model.Child; import java.util.ArrayList; import butterknife.Bind; import butterknife.ButterKnife; public class ChildAdapter extends RecyclerView.Adapter{ private ArrayList childData; private ArrayList childDataBk; public ChildAdapter(ArrayList childData) { this.childData = childData; childDataBk = new ArrayList<>(childData); } public static class ViewHolder extends RecyclerView.ViewHolder { @Bind(R.id.tv_child) TextView tvChild; @Bind(R.id.iv_expand_collapse_toggle) ImageView tvExpandCollapseToggle; public ViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemLayoutView = LayoutInflater.from(parent.getContext()) .inflate(R.layout.nested_recycler_item_child, parent, false); ChildAdapter.ViewHolder cavh = new ChildAdapter.ViewHolder(itemLayoutView); return cavh; } final Handler handler = new Handler(); Runnable collapseList = new Runnable() { @Override public void run() { if (getItemCount() > 1) { childData.remove(1); notifyDataSetChanged(); handler.postDelayed(collapseList, 50); } } }; Runnable expandList = new Runnable() { @Override public void run() { int currSize = childData.size(); if (currSize == childDataBk.size()) return; if (currSize == 0) { childData.add(childDataBk.get(currSize)); } else { childData.add(childDataBk.get(currSize)); } notifyDataSetChanged(); handler.postDelayed(expandList, 50); } }; @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { final ViewHolder vh = (ViewHolder) holder; if (position == 0 && getItemCount() == 1) { vh.tvExpandCollapseToggle.setImageResource(R.drawable.ic_expand_more_white_24dp); vh.tvExpandCollapseToggle.setVisibility(View.VISIBLE); } else if (position == childDataBk.size() - 1) { vh.tvExpandCollapseToggle.setImageResource(R.drawable.ic_expand_less_white_24dp); vh.tvExpandCollapseToggle.setVisibility(View.VISIBLE); } else { vh.tvExpandCollapseToggle.setVisibility(View.GONE); } Child c = childData.get(position); vh.tvChild.setText(c.getChild_name()); vh.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (getItemCount() > 1) { handler.post(collapseList); } else { handler.post(expandList); } } }); } @Override public int getItemCount() { return childData.size(); } }
import android.content.Context; import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import com.example.nestedrecyclerview.NestedRecyclerLinearLayoutManager; import com.example.nestedrecyclerview.R; import com.example.nestedrecyclerview.model.Child; import com.example.nestedrecyclerview.model.ParentChild; import java.util.ArrayList; import butterknife.Bind; import butterknife.ButterKnife; public class ParentAdapter extends RecyclerView.Adapter{ ArrayList parentChildData; Context ctx; public ParentAdapter(Context ctx, ArrayList parentChildData) { this.ctx = ctx; this.parentChildData = parentChildData; } public static class ViewHolder extends RecyclerView.ViewHolder { @Bind(R.id.rv_child) RecyclerView rv_child; public ViewHolder(View itemView) { super(itemView); ButterKnife.bind(this, itemView); } } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View itemLayoutView = LayoutInflater.from(parent.getContext()).inflate(R.layout.nested_recycler_item_parent, parent, false); ParentAdapter.ViewHolder pavh = new ParentAdapter.ViewHolder(itemLayoutView); return pavh; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { ViewHolder vh = (ViewHolder) holder; ParentChild p = parentChildData.get(position); initChildLayoutManager(vh.rv_child, p.getChild()); } private void initChildLayoutManager(RecyclerView rv_child, ArrayList childData) { rv_child.setLayoutManager(new NestedRecyclerLinearLayoutManager(ctx)); ChildAdapter childAdapter = new ChildAdapter(childData); rv_child.setAdapter(childAdapter); } @Override public int getItemCount() { return parentChildData.size(); } }
Layouts
activity_main.xml
nested_recycler_item_child.xml
nested_recycler_item_parent
NestedRecyclerLinearLayoutManager.java
import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.view.ViewGroup;
/**
* http://stackoverflow.com/a/32086918/2069407
*/
public class NestedRecyclerLinearLayoutManager extends LinearLayoutManager {
private static final String TAG = NestedRecyclerLinearLayoutManager.class.getSimpleName();
public NestedRecyclerLinearLayoutManager(Context context) {
super(context);
}
public NestedRecyclerLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
private int[] mMeasuredDimension = new int[2];
@Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state, int widthSpec, int heightSpec) {
final int widthMode = View.MeasureSpec.getMode(widthSpec);
final int heightMode = View.MeasureSpec.getMode(heightSpec);
final int widthSize = View.MeasureSpec.getSize(widthSpec);
final int heightSize = View.MeasureSpec.getSize(heightSpec);
int width = 0;
int height = 0;
for (int i = 0; i < getItemCount(); i++) {
measureScrapChild(recycler, i, View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
mMeasuredDimension);
if (getOrientation() == HORIZONTAL) {
width = width + mMeasuredDimension[0];
if (i == 0) {
height = mMeasuredDimension[1];
}
} else {
height = height + mMeasuredDimension[1];
if (i == 0) {
width = mMeasuredDimension[0];
}
}
}
switch (widthMode) {
case View.MeasureSpec.EXACTLY:
width = widthSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
switch (heightMode) {
case View.MeasureSpec.EXACTLY:
height = heightSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
setMeasuredDimension(width, height);
}
private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
int heightSpec, int[] measuredDimension) {
try {
View view = recycler.getViewForPosition(0); //fix IndexOutOfBoundsException
if (view != null) {
RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
getPaddingLeft() + getPaddingRight(), p.width);
int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
getPaddingTop() + getPaddingBottom(), p.height);
view.measure(childWidthSpec, childHeightSpec);
measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
recycler.recycleView(view);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
MainActivity.java
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import com.example.nestedrecyclerview.adapter.ParentAdapter;
import com.example.nestedrecyclerview.model.Child;
import com.example.nestedrecyclerview.model.ParentChild;
import java.util.ArrayList;
/**
* Reference
* https://github.com/aimanbaharum/RecyclerViewCeption
*/
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerViewParent;
ArrayList parentChildObj;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerViewParent = (RecyclerView) findViewById(R.id.rv_parent);
LinearLayoutManager manager = new LinearLayoutManager(this);
manager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerViewParent.setLayoutManager(manager);
recyclerViewParent.setHasFixedSize(true);
ParentAdapter parentAdapter = new ParentAdapter(this, createData());
recyclerViewParent.setAdapter(parentAdapter);
}
private ArrayList createData() {
parentChildObj = new ArrayList<>();
ArrayList list1 = new ArrayList<>();
ArrayList list2 = new ArrayList<>();
ArrayList list3 = new ArrayList<>();
ArrayList list4 = new ArrayList<>();
ArrayList list5 = new ArrayList<>();
for (int i = 0; i < 3; i++) {
Child c1 = new Child();
c1.setChild_name("Child 1." + (i + 1));
list1.add(c1);
}
for (int i = 0; i < 5; i++) {
Child c2 = new Child();
c2.setChild_name("Child 2." + (i + 1));
list2.add(c2);
}
for (int i = 0; i < 2; i++) {
Child c3 = new Child();
c3.setChild_name("Child 3." + (i + 1));
list3.add(c3);
}
for (int i = 0; i < 4; i++) {
Child c4 = new Child();
c4.setChild_name("Child 4." + (i + 1));
list4.add(c4);
}
for (int i = 0; i < 2; i++) {
Child c5 = new Child();
c5.setChild_name("Child 5." + (i + 1));
list5.add(c5);
}
ParentChild pc1 = new ParentChild();
pc1.setChild(list1);
parentChildObj.add(pc1);
ParentChild pc2 = new ParentChild();
pc2.setChild(list2);
parentChildObj.add(pc2);
ParentChild pc3 = new ParentChild();
pc3.setChild(list3);
parentChildObj.add(pc3);
ParentChild pc4 = new ParentChild();
pc4.setChild(list4);
parentChildObj.add(pc4);
ParentChild pc5 = new ParentChild();
pc5.setChild(list5);
parentChildObj.add(pc5);
return parentChildObj;
}
}
Search within Codexpedia
Custom Search
Search the entire web
Custom Search
Related Posts