Cómo crear RecyclerView con múltiples tipos de vistas
De Crear listas dinámicas con RecyclerView :
Cuando creamos un RecyclerView.Adapter
tenemos que especificar ViewHolder
que se vinculará con el adaptador.
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private String[] mDataset;
public MyAdapter(String[] myDataset) {
mDataset = myDataset;
}
public static class ViewHolder extends RecyclerView.ViewHolder {
public TextView mTextView;
public ViewHolder(TextView v) {
super(v);
mTextView = v;
}
}
@Override
public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.some_layout, parent, false);
//findViewById...
ViewHolder vh = new ViewHolder(v);
return vh;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.mTextView.setText(mDataset[position]);
}
@Override
public int getItemCount() {
return mDataset.length;
}
}
¿ Es posible crear RecyclerView
con múltiples tipos de vistas?
Si es posible. Simplemente implemente getItemViewType() y ocúpese del viewType
parámetro en onCreateViewHolder()
.
Entonces haces algo como:
public class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
class ViewHolder0 extends RecyclerView.ViewHolder {
...
public ViewHolder0(View itemView){
...
}
}
class ViewHolder2 extends RecyclerView.ViewHolder {
...
public ViewHolder2(View itemView){
...
}
@Override
public int getItemViewType(int position) {
// Just as an example, return 0 or 2 depending on position
// Note that unlike in ListView adapters, types don't have to be contiguous
return position % 2 * 2;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case 0: return new ViewHolder0(...);
case 2: return new ViewHolder2(...);
...
}
}
@Override
public void onBindViewHolder(final RecyclerView.ViewHolder holder, final int position) {
switch (holder.getItemViewType()) {
case 0:
ViewHolder0 viewHolder0 = (ViewHolder0)holder;
...
break;
case 2:
ViewHolder2 viewHolder2 = (ViewHolder2)holder;
...
break;
}
}
}
Si los diseños para los tipos de vista son solo unos pocos y la lógica vinculante es simple, siga la solución de Anton . Pero el código será complicado si necesita administrar diseños complejos y lógicas vinculantes.
Creo que la siguiente solución será útil para alguien que necesite manejar tipos de vistas complejos.
Clase base de DataBinder
abstract public class DataBinder<T extends RecyclerView.ViewHolder> {
private DataBindAdapter mDataBindAdapter;
public DataBinder(DataBindAdapter dataBindAdapter) {
mDataBindAdapter = dataBindAdapter;
}
abstract public T newViewHolder(ViewGroup parent);
abstract public void bindViewHolder(T holder, int position);
abstract public int getItemCount();
......
}
Las funciones necesarias para definir en esta clase son prácticamente las mismas que las de la clase de adaptador al crear el tipo de vista única.
Para cada tipo de vista, cree la clase extendiendo este DataBinder.
Clase de DataBinder de muestra
public class Sample1Binder extends DataBinder<Sample1Binder.ViewHolder> {
private List<String> mDataSet = new ArrayList();
public Sample1Binder(DataBindAdapter dataBindAdapter) {
super(dataBindAdapter);
}
@Override
public ViewHolder newViewHolder(ViewGroup parent) {
View view = LayoutInflater.from(parent.getContext()).inflate(
R.layout.layout_sample1, parent, false);
return new ViewHolder(view);
}
@Override
public void bindViewHolder(ViewHolder holder, int position) {
String title = mDataSet.get(position);
holder.mTitleText.setText(title);
}
@Override
public int getItemCount() {
return mDataSet.size();
}
public void setDataSet(List<String> dataSet) {
mDataSet.addAll(dataSet);
}
static class ViewHolder extends RecyclerView.ViewHolder {
TextView mTitleText;
public ViewHolder(View view) {
super(view);
mTitleText = (TextView) view.findViewById(R.id.title_type1);
}
}
}
Para administrar las clases de DataBinder, cree una clase de adaptador.
Clase base DataBindAdapter
abstract public class DataBindAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
return getDataBinder(viewType).newViewHolder(parent);
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int position) {
int binderPosition = getBinderPosition(position);
getDataBinder(viewHolder.getItemViewType()).bindViewHolder(viewHolder, binderPosition);
}
@Override
public abstract int getItemCount();
@Override
public abstract int getItemViewType(int position);
public abstract <T extends DataBinder> T getDataBinder(int viewType);
public abstract int getPosition(DataBinder binder, int binderPosition);
public abstract int getBinderPosition(int position);
......
}
Cree la clase extendiendo esta clase base y luego cree una instancia de las clases DataBinder y anule los métodos abstractos.
getItemCount
Devuelve el recuento total de elementos de DataBindersgetItemViewType
Define la lógica de mapeo entre la posición del adaptador y el tipo de vista.getDataBinder
Devuelve la instancia de DataBinder según el tipo de vistagetPosition
Defina la lógica de conversión a la posición del adaptador desde la posición en el DataBinder especificado.getBinderPosition
Defina la lógica de conversión a la posición en DataBinder desde la posición del adaptador.
Dejé una solución más detallada y ejemplos en GitHub, así que consulte RecyclerView-MultipleViewTypeAdapter si lo necesita.