RecyclerView Varias vistas de disposición en una clase de adaptador

Esto es lo que he logrado? 3 secciones diferentes, 10 artículos diferentes en cada sección.

Aquí está el enlace tutorial que estoy siguiendo y debajo es la Captura de pantalla :

Introduzca aquí la descripción de la imagen

Tratando de mostrar different Views para cada sección . Me gusta:

Para la Sección 1 (layout_1.xml)

Para la Sección 2 (layout_2.xml)

Para la Sección 3 (layout_3.xml)

Pero mostrar la vista de layout_1.xml de layout_1.xml en cada Sección … (Sección 1, 2, 3)

¿Puedo saber dónde estoy haciendo error en mi código, lo que he perdido?

 public class SectionListDataAdapter extends RecyclerView.Adapter<SectionListDataAdapter.SingleItemRowHolder> { private ArrayList<SingleItemModel> itemsList; private Context mContext; public SectionListDataAdapter(Context context, ArrayList<SingleItemModel> itemsList) { this.itemsList = itemsList; this.mContext = context; } @Override public SingleItemRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) { switch (i) { case 0: View viewONE = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_1, null, false); SingleItemRowHolder rowONE = new SingleItemRowHolder(viewONE); return rowONE; case 1: View viewTWO = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_2, null, false); SingleItemRowHolder rowTWO = new SingleItemRowHolder(viewTWO); return rowTWO; case 2: View viewTHREE = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_3, null, false); SingleItemRowHolder rowTHREE = new SingleItemRowHolder(viewTHREE); return rowTHREE; } return null; } @Override public void onBindViewHolder(SingleItemRowHolder holder, int i) { SingleItemModel singleItem = itemsList.get(i); holder.tvTitle.setText(singleItem.getName()); } @Override public int getItemCount() { return (null != itemsList ? itemsList.size() : 0); } public class SingleItemRowHolder extends RecyclerView.ViewHolder { protected TextView tvTitle; protected ImageView itemImage; public SingleItemRowHolder(View view) { super(view); this.tvTitle = (TextView) view.findViewById(R.id.tvTitle); this.itemImage = (ImageView) view.findViewById(R.id.itemImage); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(v.getContext(), tvTitle.getText(), Toast.LENGTH_SHORT).show(); } }); } } } 

Utilice este adaptador interior:

  @Override public int getItemViewType(int position) { if (position == 0) { return 0; } else if(position == 1){ return 1; }else{ return 2; } } 

Para utilizar múltiples diseños de acuerdo a la posición en recyclerview tienes que anular el método getItemViewType (int position) dentro del adaptador: –

  @Override public int getItemViewType(int position) { if(position==0) return 0; else if(position==1) return 1; else return 2; } 

Como se mencionó ya, con el fin de getItemViewType método de RecyclerView.Adapter clase, porque si usted verá en la aplicación de ese método, verá que acaba de regresar 0 todo el tiempo.

  public int getItemViewType(int position) { return 0; } 

Y aquí ajustado el código de su adaptador que debe resolver su problema.

 public class SectionListDataAdapter extends RecyclerView.Adapter<SectionListDataAdapter.SingleItemRowHolder> { private static final int ITEM_TYPE_ROW_1 = 0; private static final int ITEM_TYPE_ROW_2 = 1; private static final int ITEM_TYPE_ROW_3 = 2; private ArrayList<SingleItemModel> itemsList; private Context context; public SectionListDataAdapter(Context context, ArrayList<SingleItemModel> itemsList) { this.itemsList = itemsList; this.context = context; } @Override public int getItemViewType(int position) { switch (position) { case 0: return ITEM_TYPE_ROW_1; case 1: return ITEM_TYPE_ROW_2; case 2: return ITEM_TYPE_ROW_3; } throw new RuntimeException(String.format("unexpected position - %d", position)); } @Override public SingleItemRowHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) { switch (viewType) { case ITEM_TYPE_ROW_1: View viewOne = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_1, null, false); return new SingleItemRowHolder(viewOne); case ITEM_TYPE_ROW_2: View viewTwo = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_2, null, false); return new SingleItemRowHolder(viewTwo); case ITEM_TYPE_ROW_3: View viewThree = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_3, null, false); return new SingleItemRowHolder(viewThree); } throw new RuntimeException(String.format("unexpected viewType - %d", viewType)); } @Override public void onBindViewHolder(SingleItemRowHolder holder, int i) { SingleItemModel singleItem = itemsList.get(i); holder.tvTitle.setText(singleItem.getName()); } @Override public int getItemCount() { return (null != itemsList ? itemsList.size() : 0); } class SingleItemRowHolder extends RecyclerView.ViewHolder { TextView tvTitle; ImageView itemImage; public SingleItemRowHolder(View view) { super(view); this.tvTitle = (TextView) view.findViewById(R.id.tvTitle); this.itemImage = (ImageView) view.findViewById(R.id.itemImage); view.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Toast.makeText(v.getContext(), tvTitle.getText(), Toast.LENGTH_SHORT).show(); } }); } } } 

Usted puede hacerlo de una manera más simple. Pase cualquier flag mientras inicializa el adaptador.

 public class SectionListDataAdapter extends RecyclerView.Adapter<SectionListDataAdapter.SingleItemRowHolder> { private ArrayList<SingleItemModel> itemsList; private Context context; private int view; public SectionListDataAdapter(Context context, ArrayList<SingleItemModel> itemsList, int layoutFlag) { this.itemsList = itemsList; this.context = context; switch(layoutFlag) { case 0: view = R.layout.layout_1; break; case 1: view = R.layout.layout_2; break; case 2: view = R.layout.layout_3; break; } } ... ... ... } 

Utilice esta view para la referencia de diseño. Usted apenas tiene que decir qué disposición ser inflada en el momento de fijar el adaptador.

Debe anular el método

 int getItemViewType (int position) 

Recibe el número de fila y necesita devolver el "tipo" de fila, es decir, 1 2 o 3.

El resultado se pasará a onCreateViewHolder.

FYI

RecyclerView también se puede utilizar para inflar varios tipos de vista.

  • Será más fácil para usted que cree el sostenedor diferente.
  • Crear otro adaptador es mejor Soluciones

Intentar con

  @Override public SingleItemRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) { switch (i) { case 0: View viewONE = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_1, null, false); SingleItemRowHolder rowONE = new SingleItemRowHolder(viewONE); return rowONE; case 1: View viewTWO = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_2, null, false); SingleItemRowHolderTwo rowTWO = new SingleItemRowHolderTwo (viewTWO); return rowTWO; case 2: View viewTHREE = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_3, null, false); SingleItemRowHolderThree rowTHREE = new SingleItemRowHolderThree(viewTHREE); return rowTHREE; } return null; } 

Leer RecyclerView también se puede utilizar para inflar varios tipos de vista

Si por ejemplo desea mostrar esta lista de vistas:

Tipo1 tipo2 tipo3 tipo1 tipo2 tipo3

Entonces eso debería hacer el trabajo:

 public class SectionListDataAdapter extends RecyclerView.Adapter<SectionListDataAdapter.SingleItemRowHolder> { private static final int ITEM_TYPE_ROW_1 = 0; private static final int ITEM_TYPE_ROW_2 = 1; private static final int ITEM_TYPE_ROW_3 = 2; private ArrayList<SingleItemModel> itemsList; private Context context; private ArrayList<Integer> viewTypes = new ArrayList<>(); public SectionListDataAdapter(Context context, ArrayList<SingleItemModel> itemsList) { this.itemsList = itemsList; this.context = context; viewTypes.add(ITEM_TYPE_ROW_1); viewTypes.add(ITEM_TYPE_ROW_2); viewTypes.add(ITEM_TYPE_ROW_3); viewTypes.add(ITEM_TYPE_ROW_1); viewTypes.add(ITEM_TYPE_ROW_2); viewTypes.add(ITEM_TYPE_ROW_3); } @Override public int getItemViewType(int position) { return viewTypes.get(position); } @Override public int getItemCount() { return viewTypes.size(); } ....... ........ 

Si desea agregar o quitar filas, puede realizar la inserción / eliminación de viewTypes en el array viewTypes y luego llamar a los métodos de notificación de RecyclerView notifyItemInserted o notifyItemRemoved, la lista se actualizará con el nuevo orden y tipo de vistas.

Simplemente use el diseño del marco con su fragmento y agregue este fragmento en su framelayout que agregará como usted quiere para eso. Así que también es fácil de manejar. Espero que esto te ayudará

Sí, necesita reemplazar el método getItemViewType (int position) que ayuda a inflar diferentes vistas en recyclerview.

Estoy publicando un código de ejemplo que puede ayudarle.

 public class TransactionHistoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { private final int TYPE_HEADER = 1; private final int TYPE_CHILD = 2; private final Context mContext; private final List<TransactionResultEntity> mTransactionList; @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case TYPE_HEADER: View headerView = LayoutInflater.from(mContext) .inflate(R.layout.row_transaction_header, parent, false); return new ParentTypeDataObjectHolder(headerView); case TYPE_CHILD: View childView = LayoutInflater.from(mContext) .inflate(R.layout.row_transaction_child, parent, false); return new ChildTypeDataObjectHolder(childView); } return null; } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { switch (holder.getItemViewType()) { case TYPE_HEADER: ParentTypeDataObjectHolder parentTypeDataObjectHolder = (ParentTypeDataObjectHolder) holder; parentTypeDataObjectHolder.headerYearMonthTv.setText(mTransactionList.get(holder.getAdapterPosition()).getRowLabel()); break; case TYPE_CHILD: ChildTypeDataObjectHolder childTypeDataObjectHolder = (ChildTypeDataObjectHolder) holder; childTypeDataObjectHolder.txnAmountTv.setText(mTransactionList.get(holder.getAdapterPosition()).getTransactionAmount()); break; } } @Override public int getItemCount() { return mTransactionList.size(); } @Override public int getItemViewType(int position) { if (mTransactionList.get(position).getDataType() == TYPE_HEADER) return TYPE_HEADER; else return TYPE_CHILD; } class ParentTypeDataObjectHolder extends RecyclerView.ViewHolder { private final TextView headerYearMonthTv; public ParentTypeDataObjectHolder(View itemView) { super(itemView); headerYearMonthTv = (TextView) itemView.findViewById(R.id.row_transaction_header_tv); } } class ChildTypeDataObjectHolder extends RecyclerView.ViewHolder { TextView txnAmountTv; public ChildTypeDataObjectHolder(View itemView) { super(itemView); txnAmountTv = (TextView) itemView.findViewById(R.id.transaction_child_txn_amount_tv); } } 

}

Todo lo que necesitas hacer es anular el método getItemViewType() dentro de tu adaptador.

Puedes escribirlo como:

  @Override public int getItemViewType(int position) { if (position < 0) { return 0; } else if(position < 20) { return 1; } else { return 2; } } 

Ahora la lógica anterior funciona si sus itemsList ArrayList tienen los primeros 10 artículos de la sección 1, los próximos 10 artículos de la sección 2 y los 10 últimos artículos de la sección 3.

Si ese no es el caso, entonces puede tener un número entero sectionNumber en su clase SingleItemModel que especifica el número de sección a la que pertenece ese modelo. Ahora puede modificar el método getItemViewType() como

 @Override public int getItemViewType(int position) { SingleItemModel singleItemModel = itemsList.get(position); if (singleItemModel.getSection() == 1) { return 0; } else if(singleItemModel.getSection() == 2) { return 1; } else { return 2; } } 

Bueno, si lo tengo bien, quieres hacer el segundo adaptador, el que proporciona las listas de filas, variable, por lo que soporta diferentes diseños, basados ​​no en su posición, sino en algunos datos del adaptador principal (el que proporciona el Secciones). Por lo tanto, sobreescribir getItemViewType no funcionará, porque los datos de sección están contenidos en el adaptador principal, ni siquiera llega allí. Por lo tanto, el mejor y más limpio curso, sería utilizar … abstracción . Olvídate de varios usuarios. Utilice uno, y dentro de él, vincule una vista personalizada. Las vistas personalizadas proporcionarán los archivos de diseño específicos y establecerán los controles incluidos en ellos. El titular hará exactamente lo que se pretende hacer: guardar RAM mediante la reutilización de las vistas. La ventaja de esto, es que usted puede tener una jerarquía limpia, que puede crecer en complejidad en el tiempo, en lugar de un gran adaptador de grasa que se convertirá en demasiado difícil de mantener. Aquí está:

Dado que este es un montón de código para ponerlo aquí, tomé su proyecto de ejemplo y modificado para proporcionar lo que entendí que estaban tratando de hacer. Aquí está:

https://github.com/fcopardo/exampleCustomViewsInHolder/tree/master

Los aspectos interesantes:

 public class SectionListDataAdapter extends RecyclerView.Adapter<SectionListDataAdapter.SingleItemRowHolder> { private ArrayList<SingleItemModel> itemsList; private Context context; private String section; public SectionListDataAdapter(Context context, ArrayList<SingleItemModel> itemsList, String sectionName) { this.itemsList = itemsList; this.context = context; this.section = sectionName; } @Override public SingleItemRowHolder onCreateViewHolder(ViewGroup viewGroup, int i) { return new SingleItemRowHolder(RowFactory.getRow(context, section)); } @Override public void onBindViewHolder(SingleItemRowHolder holder, int i) { holder.setData(itemsList.get(i)); } @Override public int getItemCount() { return (null != itemsList ? itemsList.size() : 0); } public class SingleItemRowHolder extends RecyclerView.ViewHolder { protected AbstractRowElement rowElement; public SingleItemRowHolder(AbstractRowElement view) { super(view); this.rowElement = view; } public void setData(SingleItemModel singleItemModel){ rowElement.setItem(singleItemModel); } } } 

Este es el adaptador de disposición variable. Como puede ver, utiliza sólo un ViewHolder y una fábrica para proporcionar las instancias de vista que necesita.

 public class RowFactory { public static AbstractRowElement getRow(Context context, String name){ switch (name){ case "Section 1": return new FullRowElement(context); case "Section 2": return new TextRowElement(context); case "Section 3": return new ImageRowElement(context); default: Log.e("inflate", name); return new FullRowElement(context); } } } 

Esto proporciona las vistas personalizadas, cada una usando un diseño diferente, pero trabajando con el mismo conjunto de datos, basado en el título de la sección.

 public abstract class AbstractRowElement extends CardView{ protected int layout = 0; protected SingleItemModel singleItemModel; public AbstractRowElement(Context context) { super(context); inflateBaseLayout(); } public AbstractRowElement(Context context, AttributeSet attrs) { super(context, attrs); inflateBaseLayout(); } public AbstractRowElement(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); inflateBaseLayout(); } protected void inflateBaseLayout() { this.setContainer(); if(this.layout != 0) { LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); inflater.inflate(layout, this, true); this.inflateComponents(); } } protected abstract void setContainer(); protected abstract void inflateComponents(); public void setItem(SingleItemModel itemModel){ this.singleItemModel = itemModel; this.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { Toast.makeText(getContext(), singleItemModel.getName()+"\n"+singleItemModel.getDescription(), Toast.LENGTH_SHORT).show(); } }); setData(singleItemModel); } public abstract void setData(SingleItemModel itemModel); } 

Por último, esta es la clase de vista base para el adaptador. Las subclases definen el archivo de diseño a utilizar y ponen los datos deseados en los controles. El resto es bastante sencillo.

Sería totalmente posible hacer esto sin vistas personalizadas. Usted podría hacer algo como:

 int layoutFile = getLayoutForSection(section); View v = LayoutInflater.from(viewGroup.getContext()).inflate(layoutFile, null); 

Pero como no sé qué tan compleja es la visión que piensas crear, lo mejor es mantener las cosas bien separadas. ¡Que te diviertas!

  • Escribir texto multilínea en el botón en Android
  • Icono de elemento del cajón de navegación que no muestra el color original
  • ¿Cómo puedo crear una barra de botones de encabezado o pie de página para mi aplicación de Android?
  • Selector con android: drawable = atributo "@ color / transparent"
  • Android: textColor del botón deshabilitado en el selector no se muestra?
  • java.lang.NullPointer Excepción en getResources (). getString (R.string.value);
  • Archivo binario línea # 8: Error al inflar el fragmento de la clase, Google Maps
  • Lectura y escritura de archivos XML
  • Haga referencia al id de una vista dentro de un diseño "include" en xml
  • Tema Programáticamente establecido. Cómo volver a cargar Actividad para aplicar
  • Nuevo patrón de diseño de la actividad de Android Studio content_main.xml
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.