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.
This question is related to
java
android
android-recyclerview
android-cardview
you can use LayoutInflater to inflate your dynamic data as a layout file.
UPDATE : first create a LinearLayout inside your CardView's layout and assign an ID for it.
after that create a layout file that you want to inflate. at last in your onBindViewHolder
method in your "RAdaper" class. write these codes :
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = mInflater.inflate(R.layout.my_list_custom_row, parent, false);
after that you can initialize data and ClickListeners with your RAdapter Data. hope it helps.
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();
}
}
}
Source: Stackoverflow.com