studio recyclerview personalizado linearlayout implement ejemplo developer create cardview card app java android android-recyclerview android-cardview

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.

this y this puede ser útil :)