java - personalizado - Cómo agregar un recyclerView dentro de otro recyclerView
recyclerview android studio ejemplo (3)
Estoy planeando desarrollar una aplicación que muestre algunos datos dinámicos dentro de un
recyclerCardView
.
Así que decidí agregar un
recyclerView
llamado
CheckBoxRecyclerView
dentro de mi
recyclerView
principal.
Este es mi código para mi aplicación:
Mi actividad principal:
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{
}
Y es el archivo de diseño:
<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">
y dentro de este recyclerView hay otro:
<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>
Sus adaptadores, 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();
}
}
Y segundo adaptador:
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();
}
}
Y mi problema: como ves en CAdapter, solo se muestra el mensaje de registro del constructor.
ACTUALIZACIÓN
: si hay otra forma de mostrar algunos datos dinámicos dentro de otra tarjeta dinámica, en caso afirmativo, ¿es mejor usarlo en lugar de recyclerView?
alguien me ayuda?
El resultado: el resultado de la
aplicación,
como ve, solo funciona setTitle for RAdapter.
Me encontré con un problema similar hace un tiempo y lo que sucedía en mi caso era que la vista del reciclador externo funcionaba perfectamente bien, pero el adaptador de la vista del reciclador interno / segundo tenía problemas menores, todos los métodos como el constructor se iniciaron e incluso el método getCount () se estaba llamando, aunque los métodos finales responsables de generar vista es decir ..
1. Los métodos onBindViewHolder () nunca fueron llamados. -> Problema 1.
2. Cuando se llamó finalmente, nunca muestra los elementos de la lista / filas de la vista del reciclador. -> Problema 2.
Razón por la que sucedió esto : cuando coloca una vista de reciclador dentro de otra vista de reciclador, la altura de la vista de reciclador primera / externa no se ajusta automáticamente. Se define cuando se crea la primera vista / exterior y luego permanece fija. En ese momento, su segunda vista de reciclador interno aún no ha cargado sus elementos y, por lo tanto, su altura se establece en cero y nunca cambia incluso cuando obtiene datos. Luego, cuando se llama a onBindViewHolder () en su segunda vista de reciclador interno, obtiene elementos pero no tiene espacio para mostrarlos porque su altura aún es cero. Por lo tanto, los elementos en la segunda vista de reciclador nunca se muestran, incluso cuando onBindViewHolder () los ha agregado.
Solución
:: debe crear su LinearLayoutManager personalizado para la segunda vista de reciclador y eso es todo.
Para crear su propio LinearLayoutManager:
Cree una clase Java con el nombre
CustomLinearLayoutManager
y pegue el siguiente código en él.
NO SE REQUIEREN CAMBIOS
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();
}
}
}
Me gustaría sugerirle que use un solo
RecyclerView
y
RecyclerView
dinámicamente los elementos de su lista.
He agregado un
proyecto github
para describir cómo se puede hacer esto.
Puedes echar un vistazo.
Si bien las otras soluciones funcionarán bien, me gustaría sugerir que esta es una forma mucho más rápida y eficiente de mostrar múltiples listas en un
RecyclerView
.
La idea es agregar lógica en su método
onCreateViewHolder
y
onBindViewHolder
para que pueda inflar la vista adecuada para las posiciones exactas en su
RecyclerView
.
También agregué un proyecto de muestra junto con esa wiki. Puede clonar y verificar lo que hace. Por conveniencia, estoy publicando el adaptador que he usado.
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);
}
}
Hay otra forma de mantener sus elementos en una sola
ArrayList
de objetos para que pueda establecer un atributo que etiquete los elementos para indicar qué elemento pertenece a la primera lista y cuál pertenece a la segunda lista.
Luego pase esa
ArrayList
en su
RecyclerView
y luego implemente la lógica dentro del adaptador para llenarlas dinámicamente.
Espero que ayude.
puede usar LayoutInflater para inflar sus datos dinámicos como un archivo de diseño.
ACTUALIZACIÓN
: primero cree un LinearLayout dentro del diseño de su CardView y asígnele una ID.
después de eso, cree un archivo de diseño que desee inflar.
por fin en su método
onBindViewHolder
en su clase "RAdaper".
escribe estos códigos:
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = mInflater.inflate(R.layout.my_list_custom_row, parent, false);
después de eso, puede inicializar datos y ClickListeners con sus datos RAdapter. Espero eso ayude.