Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add a recyclerView inside another recyclerView

I'm planning to develop an app that shows some dynamic data inside a recyclerCardView. So i decided add a recyclerView called CheckBoxRecyclerView inside my main recyclerView. This is my code for my app :

My Main Activity :

setContentView(R.layout.activity_startup); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); reminderView = (RecyclerView) findViewById(R.id.reminder_recycler_view); RlayoutManager = new LinearLayoutManager(this); reminderView.setLayoutManager(RlayoutManager);  setSupportActionBar(toolbar); cardView = (CardView) findViewById(R.id.card_first); cardView.setOnClickListener(new View.OnClickListener() {     @Override     public void onClick(View v) {         Intent intent = new Intent(getApplicationContext() , ReminderActivity.class);         startActivity(intent);     } }); ReminderHelper helper = new ReminderHelper(getApplicationContext()); ReminderAdapter reminderAdapter = new ReminderAdapter(helper); ContentValues reminderValues = new ContentValues(); ContentValues checkboxValues = new ContentValues(); // Devlopment Part -> reminderValues.put("reminderTitle" , "A Reminder Title"); reminderValues.put("reminderLastModDate" , 0); reminderValues.put("reminderAlarm" , 0); reminderValues.put("reminderPicURI" , "skjshksjh"); reminderValues.put("ReminderBackground" , "#00796b"); checkboxValues.put("checkboxText" , "This is a CheckBox"); checkboxValues.put("isDone" , false); checkboxValues.put("checkboxReminderID" , 0); reminderAdapter.INSERT_REMINDER(reminderValues); reminderAdapter.INSERT_CHECKBOX(checkboxValues); File dbPath = getApplicationContext().getDatabasePath(ReminderHelper.DATABASE_NAME); if(dbPath.exists()){     List<Reminder> reminders = new ReminderAdapter(helper).getAllReminders();     List<CheckBoxItem> checkBoxItems = new ReminderAdapter(helper).getAllCheckBoxes();     RAdapter = new RAdapter(reminders , getApplicationContext() , checkBoxItems);     reminderView.setAdapter(RAdapter); }else{  } 

And it's layout file :

<LinearLayout 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="match_parent"     android:orientation="vertical"     android:paddingBottom="8dp"     android:paddingLeft="8dp"     android:paddingRight="8dp"     android:paddingTop="8dp"     app:layout_behavior="@string/appbar_scrolling_view_behavior"     tools:context="com.smflog.sreminder.StartupActivity"     tools:showIn="@layout/app_bar_startup">      <android.support.v7.widget.RecyclerView         android:layout_width="match_parent"         android:id="@+id/reminder_recycler_view"         android:scrollbars="vertical"         android:layout_height="match_parent"> 

and inside this recyclerView there is another:

<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:card_view="http://schemas.android.com/apk/res-auto"     android:layout_width="match_parent"     android:layout_height="wrap_content"     android:id="@+id/reminder_card"     card_view:cardCornerRadius="2dp"     card_view:cardElevation="4dp"     card_view:cardUseCompatPadding="true">      <LinearLayout         android:layout_width="match_parent"         android:layout_height="match_parent"         android:orientation="vertical"         android:paddingBottom="16dp"         android:paddingLeft="8dp">          <com.smflog.sreminder.utils.TitleView             android:layout_width="wrap_content"             android:layout_height="wrap_content"             android:id="@+id/reminder_title"             android:paddingTop="8dp"             android:text="Wellcome To Google Keep !"             android:textSize="15dp"             android:textStyle="bold" />         <LinearLayout             android:layout_width="wrap_content"             android:layout_height="wrap_content" android:orientation="horizontal"> <android.support.v7.widget.RecyclerView     android:layout_width="wrap_content"     android:id="@+id/checkbox_recycler_view"     android:layout_height="wrap_content">  </android.support.v7.widget.RecyclerView>         </LinearLayout>      </LinearLayout> </android.support.v7.widget.CardView> 

Their adapters, Main ( RAdapter ) :

public class RAdapter extends RecyclerView.Adapter<RAdapter.ViewHolder> {     List<Reminder> reminder;     private Context context;     private LinearLayoutManager lln;     private CAdapter checkBoxAdapter;     private List<CheckBoxItem> checkBoxItems;     public static class ViewHolder extends RecyclerView.ViewHolder {         public CardView rCardView;         public RecyclerView recyclerView;         public TitleView rTitleView;         public ViewHolder(View itemView) {             super(itemView);             rCardView = (CardView) itemView.findViewById(R.id.reminder_card);             rTitleView = (TitleView) itemView.findViewById(R.id.reminder_title);             recyclerView = (RecyclerView) itemView.findViewById(R.id.checkbox_recycler_view);         }     }      public RAdapter(List<Reminder> reminder, Context context, List<CheckBoxItem> checkBoxItems) {         this.reminder = reminder;         this.context = context;         this.checkBoxItems = checkBoxItems;     }      @Override     public RAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {         View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.reminder_card, parent, false);         ViewHolder vh = new ViewHolder(v);         return vh;     }      @Override     public void onBindViewHolder(RAdapter.ViewHolder holder, int position) {         lln = new LinearLayoutManager(context);         holder.recyclerView.setLayoutManager(lln);         checkBoxAdapter = new CAdapter(checkBoxItems, context);         holder.recyclerView.setAdapter(checkBoxAdapter);         holder.rCardView.setCardBackgroundColor(Color.parseColor("#00796b"));         holder.rTitleView.setText(reminder.get(position).getReminderTitle());     }      @Override     public int getItemCount() {         return reminder.size();     } } 

And second Adapter :

public class CAdapter extends RecyclerView.Adapter<CAdapter.ViewHolder> {     List<CheckBoxItem> checkBoxItems;     Context context;      public static class ViewHolder extends RecyclerView.ViewHolder {         public TitleView checkBoxTitle;         public ImageView deleteCheckBox;         public CheckBox checkBoxCheckBox;          public ViewHolder(View itemView) {             super(itemView);             checkBoxTitle = (TitleView) itemView.findViewById(R.id.checkbox_item_text);             checkBoxCheckBox = (CheckBox) itemView.findViewById(R.id.checkbox_item_checkbox);             Log.d("CAdapterLog", "Adpater Holded !!!!! :( ");             deleteCheckBox = (ImageView) itemView.findViewById(R.id.btn_delete_checkbox);         }     }      public CAdapter(List<CheckBoxItem> checkBoxItems, Context context) {         this.checkBoxItems = checkBoxItems;         this.context = context;         Log.d("CAdapterLog", "Adpater Created !!!!! :( ");     }       @Override     public CAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {         View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.checkbox_item, parent, false);         ViewHolder vh = new ViewHolder(v);         Log.d("CAdapterLog", "Adpater ViewHolded :( !!!!! :( ");         return vh;     }      @Override     public void onBindViewHolder(CAdapter.ViewHolder holder, int position) {         Boolean isCheckboxChecked = Boolean.parseBoolean(checkBoxItems.get(position).getCheckBoxIsDone());         String checkBoxText = checkBoxItems.get(position).getCheckBoxBody();         Log.d("CAdapterLog", "Adpater Binded :( ");         final int checkboxID = Integer.parseInt(checkBoxItems.get(position).getCheckBoxID());         int reminderCheckBoxID = Integer.parseInt(checkBoxItems.get(position).getCheckBoxReminderID());         holder.deleteCheckBox.setOnClickListener(new View.OnClickListener() {             @Override             public void onClick(View v) {                 Log.d("CAdapterLog", "Cross Button Clicked !");             }         });         holder.checkBoxCheckBox.setChecked(isCheckboxChecked);         holder.checkBoxTitle.setText(checkBoxText);     }      @Override     public int getItemCount() {         return checkBoxItems.size();     }  } 

And my problem: as you see in CAdapter, only constructor's Log message displayed.

UPDATE: if there is another way to display some dynamic data inside another dynamic card if yes is it better to use it instead of recyclerView?
anyone help me?
The output : Application output as you see just the setTitle for RAdapter works.

like image 819
Mohammad Fatemi Avatar asked Jan 02 '16 18:01

Mohammad Fatemi


People also ask

Can you have a RecyclerView inside a RecyclerView?

A nested RecyclerView is an implementation of a RecyclerView within a RecyclerView. An example of such a layout can be seen in a variety of apps such as the Play store where the outer (parent) RecyclerView is of Vertical orientation whereas the inner (child) RecyclerViews are of horizontal orientations.

Can we use RecyclerView inside RecyclerView in Android?

You should not put multiple RecyclerViews inside each other.


2 Answers

I would like to suggest to use a single RecyclerView and populate your list items dynamically. I've added a github project to describe how this can be done. You might have a look. While the other solutions will work just fine, I would like to suggest, this is a much faster and efficient way of showing multiple lists in a RecyclerView.

The idea is to add logic in your onCreateViewHolder and onBindViewHolder method so that you can inflate proper view for the exact positions in your RecyclerView.

I've added a sample project along with that wiki too. You might clone and check what it does. For convenience, I am posting the adapter that I have used.

public class DynamicListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {      private static final int FOOTER_VIEW = 1;     private static final int FIRST_LIST_ITEM_VIEW = 2;     private static final int FIRST_LIST_HEADER_VIEW = 3;     private static final int SECOND_LIST_ITEM_VIEW = 4;     private static final int SECOND_LIST_HEADER_VIEW = 5;      private ArrayList<ListObject> firstList = new ArrayList<ListObject>();     private ArrayList<ListObject> secondList = new ArrayList<ListObject>();      public DynamicListAdapter() {     }      public void setFirstList(ArrayList<ListObject> firstList) {         this.firstList = firstList;     }      public void setSecondList(ArrayList<ListObject> secondList) {         this.secondList = secondList;     }      public class ViewHolder extends RecyclerView.ViewHolder {         // List items of first list         private TextView mTextDescription1;         private TextView mListItemTitle1;          // List items of second list         private TextView mTextDescription2;         private TextView mListItemTitle2;          // Element of footer view         private TextView footerTextView;          public ViewHolder(final View itemView) {             super(itemView);              // Get the view of the elements of first list             mTextDescription1 = (TextView) itemView.findViewById(R.id.description1);             mListItemTitle1 = (TextView) itemView.findViewById(R.id.title1);              // Get the view of the elements of second list             mTextDescription2 = (TextView) itemView.findViewById(R.id.description2);             mListItemTitle2 = (TextView) itemView.findViewById(R.id.title2);              // Get the view of the footer elements             footerTextView = (TextView) itemView.findViewById(R.id.footer);         }          public void bindViewSecondList(int pos) {              if (firstList == null) pos = pos - 1;             else {                 if (firstList.size() == 0) pos = pos - 1;                 else pos = pos - firstList.size() - 2;             }              final String description = secondList.get(pos).getDescription();             final String title = secondList.get(pos).getTitle();              mTextDescription2.setText(description);             mListItemTitle2.setText(title);         }          public void bindViewFirstList(int pos) {              // Decrease pos by 1 as there is a header view now.             pos = pos - 1;              final String description = firstList.get(pos).getDescription();             final String title = firstList.get(pos).getTitle();              mTextDescription1.setText(description);             mListItemTitle1.setText(title);         }          public void bindViewFooter(int pos) {             footerTextView.setText("This is footer");         }     }      public class FooterViewHolder extends ViewHolder {         public FooterViewHolder(View itemView) {             super(itemView);         }     }      private class FirstListHeaderViewHolder extends ViewHolder {         public FirstListHeaderViewHolder(View itemView) {             super(itemView);         }     }      private class FirstListItemViewHolder extends ViewHolder {         public FirstListItemViewHolder(View itemView) {             super(itemView);         }     }      private class SecondListHeaderViewHolder extends ViewHolder {         public SecondListHeaderViewHolder(View itemView) {             super(itemView);         }     }      private class SecondListItemViewHolder extends ViewHolder {         public SecondListItemViewHolder(View itemView) {             super(itemView);         }     }      @Override     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {          View v;          if (viewType == FOOTER_VIEW) {             v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_footer, parent, false);             FooterViewHolder vh = new FooterViewHolder(v);             return vh;          } else if (viewType == FIRST_LIST_ITEM_VIEW) {             v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_first_list, parent, false);             FirstListItemViewHolder vh = new FirstListItemViewHolder(v);             return vh;          } else if (viewType == FIRST_LIST_HEADER_VIEW) {             v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_first_list_header, parent, false);             FirstListHeaderViewHolder vh = new FirstListHeaderViewHolder(v);             return vh;          } else if (viewType == SECOND_LIST_HEADER_VIEW) {             v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_second_list_header, parent, false);             SecondListHeaderViewHolder vh = new SecondListHeaderViewHolder(v);             return vh;          } else {             // SECOND_LIST_ITEM_VIEW             v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_item_second_list, parent, false);             SecondListItemViewHolder vh = new SecondListItemViewHolder(v);             return vh;         }     }      @Override     public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {          try {             if (holder instanceof SecondListItemViewHolder) {                 SecondListItemViewHolder vh = (SecondListItemViewHolder) holder;                 vh.bindViewSecondList(position);              } else if (holder instanceof FirstListHeaderViewHolder) {                 FirstListHeaderViewHolder vh = (FirstListHeaderViewHolder) holder;              } else if (holder instanceof FirstListItemViewHolder) {                 FirstListItemViewHolder vh = (FirstListItemViewHolder) holder;                 vh.bindViewFirstList(position);              } else if (holder instanceof SecondListHeaderViewHolder) {                 SecondListHeaderViewHolder vh = (SecondListHeaderViewHolder) holder;              } else if (holder instanceof FooterViewHolder) {                 FooterViewHolder vh = (FooterViewHolder) holder;                 vh.bindViewFooter(position);             }         } catch (Exception e) {             e.printStackTrace();         }     }      @Override     public int getItemCount() {          int firstListSize = 0;         int secondListSize = 0;          if (secondList == null && firstList == null) return 0;          if (secondList != null)             secondListSize = secondList.size();         if (firstList != null)             firstListSize = firstList.size();          if (secondListSize > 0 && firstListSize > 0)             return 1 + firstListSize + 1 + secondListSize + 1;   // first list header, first list size, second list header , second list size, footer         else if (secondListSize > 0 && firstListSize == 0)             return 1 + secondListSize + 1;                       // second list header, second list size, footer         else if (secondListSize == 0 && firstListSize > 0)             return 1 + firstListSize;                            // first list header , first list size         else return 0;     }      @Override     public int getItemViewType(int position) {          int firstListSize = 0;         int secondListSize = 0;          if (secondList == null && firstList == null)             return super.getItemViewType(position);          if (secondList != null)             secondListSize = secondList.size();         if (firstList != null)             firstListSize = firstList.size();          if (secondListSize > 0 && firstListSize > 0) {             if (position == 0) return FIRST_LIST_HEADER_VIEW;             else if (position == firstListSize + 1)                 return SECOND_LIST_HEADER_VIEW;             else if (position == secondListSize + 1 + firstListSize + 1)                 return FOOTER_VIEW;             else if (position > firstListSize + 1)                 return SECOND_LIST_ITEM_VIEW;             else return FIRST_LIST_ITEM_VIEW;          } else if (secondListSize > 0 && firstListSize == 0) {             if (position == 0) return SECOND_LIST_HEADER_VIEW;             else if (position == secondListSize + 1) return FOOTER_VIEW;             else return SECOND_LIST_ITEM_VIEW;          } else if (secondListSize == 0 && firstListSize > 0) {             if (position == 0) return FIRST_LIST_HEADER_VIEW;             else return FIRST_LIST_ITEM_VIEW;         }          return super.getItemViewType(position);     } } 

There is another way of keeping your items in a single ArrayList of objects so that you can set an attribute tagging the items to indicate which item is from first list and which one belongs to second list. Then pass that ArrayList into your RecyclerView and then implement the logic inside adapter to populate them dynamically.

Hope that helps.

like image 96
Reaz Murshed Avatar answered Sep 20 '22 09:09

Reaz Murshed


I ran into similar problem a while back and what was happening in my case was the outer recycler view was working perfectly fine but the the adapter of inner/second recycler view had minor issues all the methods like constructor got initiated and even getCount() method was being called, although the final methods responsible to generate view ie..

1. onBindViewHolder() methods never got called. --> Problem 1.

2. When it got called finally it never show the list items/rows of recycler view. --> Problem 2.

Reason why this happened :: When you put a recycler view inside another recycler view, then height of the first/outer recycler view is not auto adjusted. It is defined when the first/outer view is created and then it remains fixed. At that point your second/inner recycler view has not yet loaded its items and thus its height is set as zero and never changes even when it gets data. Then when onBindViewHolder() in your second/inner recycler view is called, it gets items but it doesn't have the space to show them because its height is still zero. So the items in the second recycler view are never shown even when the onBindViewHolder() has added them to it.

Solution :: you have to create your custom LinearLayoutManager for the second recycler view and that is it. To create your own LinearLayoutManager: Create a Java class with the name CustomLinearLayoutManager and paste the code below into it. NO CHANGES REQUIRED

public class CustomLinearLayoutManager extends LinearLayoutManager {      private static final String TAG = CustomLinearLayoutManager.class.getSimpleName();      public CustomLinearLayoutManager(Context context) {         super(context);      }      public CustomLinearLayoutManager(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(position);              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();         }     } } 
like image 28
Khay Avatar answered Sep 19 '22 09:09

Khay