Recyclerview y manejo de diferentes tipos de inflado de filas

124

Estoy tratando de trabajar con la nueva RecyclerView, pero no pude encontrar un ejemplo de una RecyclerViewcon diferentes tipos de filas / vistas de tarjeta infladas.

Con ListViewanulo el getViewTypeCounty getItemViewType, para manejar diferentes tipos de filas.

¿Se supone que debo hacerlo de la manera "antigua" o debería hacer algo LayoutManager? Me preguntaba si alguien podría señalarme en la dirección correcta. Porque solo puedo encontrar ejemplos con un tipo.

Quiero tener una lista de tarjetas ligeramente diferentes. ¿O debería usar un scrollViewcon cardViewsdentro ... hacerlo sin el adaptador y recyclerView?

Lokkio
fuente
¿Cuál es la diferencia entre sus tipos de artículos? ¿Cómo debería reaccionar la vista del reciclador a los diferentes tipos? En general, no hay nada que pueda hacer con una vista de desplazamiento / vista de lista que no puede hacer con una vista de reciclador, pero no al revés
Gil Moshay del
En realidad es como lo que ves en la tienda de Google Play. En la parte superior puede tener un encabezado, luego puede ver tres tarjetas, luego tiene una sección con información. ¿Se hace esto en una vista de lista de reciclaje? O scrollview? Porque si es una vista de desplazamiento, necesito determinar todos los diseños antes. Con una vista de lista, puedo agregar ciertos objetos a mi conjunto de datos y el diseño correcto se inflará. Entonces, quiero saber cómo hacer la última parte con la nueva Recyclerview, ¿necesito anular métodos como listview?
Lokkio
AnyOne en busca de la demostración de github para el diseño de varias filas utilizando el reciclador code2concept.blogspot.in/2015/10/…
nitesh
Verifique este enlace, funcionará para usted: stackoverflow.com/a/39972276/3946958
Ravindra Kushwaha

Respuestas:

202

Sin embargo, manejar la lógica de filas / secciones similar a UITableView de iOS no es tan simple en Android como en iOS, cuando usa RecyclerView: la flexibilidad de lo que puede hacer es mucho mayor.

Al final, se trata de cómo averiguar qué tipo de vista está mostrando en el Adaptador. Una vez que lo hayas resuelto, debería ser fácil navegar (en realidad no, pero al menos lo tendrás ordenado).

El adaptador expone dos métodos que debe anular:

getItemViewType(int position)

La implementación predeterminada de este método siempre devolverá 0, lo que indica que solo hay 1 tipo de vista. En su caso, no es así, por lo que necesitará encontrar una manera de afirmar qué fila corresponde a qué tipo de vista. A diferencia de iOS, que maneja esto para usted con filas y secciones, aquí solo tendrá un índice en el que confiar, y deberá usar sus habilidades de desarrollador para saber cuándo una posición se correlaciona con un encabezado de sección, y cuándo se correlaciona con Una fila normal.

createViewHolder(ViewGroup parent, int viewType)

Necesitas anular este método de todos modos, pero generalmente las personas simplemente ignoran el parámetro viewType. Según el tipo de vista, deberá inflar el recurso de diseño correcto y crear su titular de vista en consecuencia. RecyclerView manejará el reciclaje de diferentes tipos de vista de una manera que evite el choque de diferentes tipos de vista.

Si planea usar un LayoutManager predeterminado, como LinearLayoutManager, debería estar listo. Si planea hacer su propia implementación de LayoutManager, deberá trabajar un poco más duro. La única API con la que realmente tiene que trabajar es la findViewByPosition(int position)que proporciona una vista determinada en una posición determinada. Dado que probablemente querrá diseñarlo de manera diferente según el tipo de vista que tenga, tiene algunas opciones:

  1. Por lo general, cuando usa el patrón ViewHolder, establece la etiqueta de la vista con el titular de la vista. Puede usar esto durante el tiempo de ejecución en el administrador de diseño para averiguar qué tipo de vista es agregando un campo en el titular de la vista que expresa esto.

  2. Dado que necesitará una función que determine qué posición se correlaciona con qué tipo de vista, también podría hacer que este método sea accesible globalmente de alguna manera (¿tal vez una clase singleton que gestione los datos?), Y luego simplemente puede consultar el mismo método de acuerdo con la posición.

Aquí hay una muestra de código:

// in this sample, I use an object array to simulate the data of the list. 
// I assume that if the object is a String, it means I should display a header with a basic title.
// If not, I assume it's a custom model object I created which I will use to bind my normal rows.
private Object[] myData;

public static final int ITEM_TYPE_NORMAL = 0;
public static final int ITEM_TYPE_HEADER = 1;

public class MyAdapter extends Adapter<ViewHolder> {

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {

        if (viewType == ITEM_TYPE_NORMAL) {
            View normalView = LayoutInflater.from(getContext()).inflate(R.layout.my_normal_row, null);
            return new MyNormalViewHolder(normalView); // view holder for normal items
        } else if (viewType == ITEM_TYPE_HEADER) {
            View headerRow = LayoutInflater.from(getContext()).inflate(R.layout.my_header_row, null);
            return new MyHeaderViewHolder(headerRow); // view holder for header items
        }
    }


    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {

        final int itemType = getItemViewType(position);

        if (itemType == ITEM_TYPE_NORMAL) {
            ((MyNormalViewHolder)holder).bindData((MyModel)myData[position]);
        } else if (itemType == ITEM_TYPE_HEADER) {
            ((MyHeaderViewHolder)holder).setHeaderText((String)myData[position]);
        }
    }

    @Override
    public int getItemViewType(int position) {
        if (myData[position] instanceof String) {
            return ITEM_TYPE_HEADER;
        } else {
            return ITEM_TYPE_NORMAL;
        }
    }

    @Override
    public int getItemCount() {
        return myData.length;
    }
}

Aquí hay una muestra de cómo deberían ser estos titulares de vistas:

public MyHeaderViewHolder extends ViewHolder {

    private TextView headerLabel;    

    public MyHeaderViewHolder(View view) {
        super(view);

        headerLabel = (TextView)view.findViewById(R.id.headerLabel);
    }

    public void setHeaderText(String text) {
        headerLabel.setText(text);
    }    
}


public MyNormalViewHolder extends ViewHolder {

    private TextView titleLabel;
    private TextView descriptionLabel;    

    public MyNormalViewHolder(View view) {
        super(view);

        titleLabel = (TextView)view.findViewById(R.id.titleLabel);
        descriptionLabel = (TextView)view.findViewById(R.id.descriptionLabel);
    }

    public void bindData(MyModel model) {
        titleLabel.setText(model.getTitle());
        descriptionLabel.setText(model.getDescription());
    }    
}

Por supuesto, este ejemplo supone que ha construido su fuente de datos (myData) de una manera que facilita la implementación de un adaptador de esta manera. Como ejemplo, le mostraré cómo construiría una fuente de datos que muestre una lista de nombres y un encabezado cada vez que cambie la primera letra del nombre (suponga que la lista está alfabetizada), de forma similar a cómo un contacto la lista se vería así:

// Assume names & descriptions are non-null and have the same length.
// Assume names are alphabetized
private void processDataSource(String[] names, String[] descriptions) {
    String nextFirstLetter = "";
    String currentFirstLetter;

    List<Object> data = new ArrayList<Object>();

    for (int i = 0; i < names.length; i++) {
        currentFirstLetter = names[i].substring(0, 1); // get the 1st letter of the name

        // if the first letter of this name is different from the last one, add a header row
        if (!currentFirstLetter.equals(nextFirstLetter)) {
            nextFirstLetter = currentFirstLetter;
            data.add(nextFirstLetter);
        }

        data.add(new MyModel(names[i], descriptions[i]));
    }

    myData = data.toArray();
}

Este ejemplo viene a resolver un problema bastante específico, pero espero que le brinde una buena visión general sobre cómo manejar diferentes tipos de filas en un reciclador y le permita realizar las adaptaciones necesarias en su propio código para satisfacer sus necesidades.

Gil Moshayof
fuente
Bastante impresionante, y creo que esta es una gran muestra para resolver este problema Solución de muestra
Amt87
Otro ejemplo para inflar las diferentes filas dentro de la vista de reciclaje que es: - stackoverflow.com/a/39972276/3946958
Ravindra Kushwaha
Debería sernames[i].substring(0, 1)
Kyle
1
Además, para las vistas de reciclador con elementos heterogéneos, también es una buena idea mirar SpanSizeLookup. stackoverflow.com/questions/26869312/…
Mahori
Es útil. Basándome en esta respuesta, también tengo una idea para implementar la vista de varios tipos en el adaptador mediante el uso de la enumeración. La enumeración tendrá un método onCreateViewHolderque nos ayudará a crear el titular de la vista. Para obtener más detalles, puede consultar mi parte: stackoverflow.com/questions/47245398/…
quangson91
114

El truco es crear subclases de ViewHolder y luego emitirlos.

public class GroupViewHolder extends RecyclerView.ViewHolder {
    TextView mTitle;
    TextView mContent;
    public GroupViewHolder(View itemView) {
        super (itemView);
        // init views...
    }
}

public class ImageViewHolder extends RecyclerView.ViewHolder {
    ImageView mImage;
    public ImageViewHolder(View itemView) {
        super (itemView);
        // init views...
    }
}

private static final int TYPE_IMAGE = 1;
private static final int TYPE_GROUP = 2;  

Y luego, en tiempo de ejecución, haga algo como esto:

@Override
public int getItemViewType(int position) {
    // here your custom logic to choose the view type
    return position == 0 ? TYPE_IMAGE : TYPE_GROUP;
}

@Override
public void onBindViewHolder (ViewHolder viewHolder, int i) {

    switch (viewHolder.getItemViewType()) {

        case TYPE_IMAGE:
            ImageViewHolder imageViewHolder = (ImageViewHolder) viewHolder;
            imageViewHolder.mImage.setImageResource(...);
            break;

        case TYPE_GROUP:
            GroupViewHolder groupViewHolder = (GroupViewHolder) viewHolder;
            groupViewHolder.mContent.setText(...)
            groupViewHolder.mTitle.setText(...);
            break;
    }
}

Espero eso ayude.

ticofab
fuente
3
Esta es la respuesta directa a la pregunta. La única parte que falta es la necesidad de anular onCreateViewHolder (ViewGroup parent, int viewType) y manejar diferentes tipos de vista basados ​​en viewType
user1928896
Otro ejemplo para inflar las diferentes filas dentro de la vista de reciclaje que es: - stackoverflow.com/questions/39971350/…
Ravindra Kushwaha
1
¿Existe alguna solución genérica en lugar de convertir la base del soporte de vista en valores de mayúsculas y minúsculas?
Vahid Ghadiri
33

Según la gran respuesta de Gil, resolví Anulando getItemViewType como lo explicó Gil. Su respuesta es excelente y debe marcarse como correcta. En cualquier caso, agrego el código para alcanzar el puntaje:

En su adaptador de reciclador:

@Override
public int getItemViewType(int position) {
    int viewType = 0;
    // add here your booleans or switch() to set viewType at your needed
    // I.E if (position == 0) viewType = 1; etc. etc.
    return viewType;
}

@Override
public FileViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if (viewType == 0) {
        return new MyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.my_layout_for_first_row, parent, false));
    }

    return new MyViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.my_other_rows, parent, false));
}

Al hacer esto, puede establecer cualquier diseño personalizado para cualquier fila.

iGio90
fuente
18
Solo un comentario menor: el segundo parámetro en onCreateViewHolder debería ser viewType, no el índice. De acuerdo con API: developer.android.com/reference/android/support/v7/widget/… , int)
Mark Martinsson
pero ¿qué pasa cuando el usuario se desplaza rápido en ese momento y obtengo un resultado extraño?
Rjz Satvara
15

Es bastante complicado pero demasiado difícil, solo copie el código a continuación y listo

package com.yuvi.sample.main;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;


import com.yuvi.sample.R;

import java.util.List;

/**
 * Created by yubraj on 6/17/15.
 */

public class NavDrawerAdapter extends RecyclerView.Adapter<NavDrawerAdapter.MainViewHolder> {
    List<MainOption> mainOptionlist;
    Context context;
    private static final int TYPE_PROFILE = 1;
    private static final int TYPE_OPTION_MENU = 2;
    private int selectedPos = 0;
    public NavDrawerAdapter(Context context){
        this.mainOptionlist = MainOption.getDrawableDataList();
        this.context = context;
    }

    @Override
    public int getItemViewType(int position) {
        return (position == 0? TYPE_PROFILE : TYPE_OPTION_MENU);
    }

    @Override
    public MainViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        switch (viewType){
            case TYPE_PROFILE:
                return new ProfileViewHolder(LayoutInflater.from(context).inflate(R.layout.row_profile, parent, false));
            case TYPE_OPTION_MENU:
                return new MyViewHolder(LayoutInflater.from(context).inflate(R.layout.row_nav_drawer, parent, false));
        }
        return null;
    }

    @Override
    public void onBindViewHolder(MainViewHolder holder, int position) {
        if(holder.getItemViewType() == TYPE_PROFILE){
            ProfileViewHolder mholder = (ProfileViewHolder) holder;
            setUpProfileView(mholder);
        }
        else {
            MyViewHolder mHolder = (MyViewHolder) holder;
            MainOption mo = mainOptionlist.get(position);
            mHolder.tv_title.setText(mo.title);
            mHolder.iv_icon.setImageResource(mo.icon);
            mHolder.itemView.setSelected(selectedPos == position);
        }
    }

    private void setUpProfileView(ProfileViewHolder mholder) {

    }

    @Override
    public int getItemCount() {
        return mainOptionlist.size();
    }




public class MyViewHolder extends MainViewHolder{
    TextView tv_title;
    ImageView iv_icon;

    public MyViewHolder(View v){
        super(v);
        this.tv_title = (TextView) v.findViewById(R.id.tv_title);
        this.iv_icon = (ImageView) v.findViewById(R.id.iv_icon);
        v.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // Redraw the old selection and the new
                notifyItemChanged(selectedPos);
                selectedPos = getLayoutPosition();
                notifyItemChanged(selectedPos);
            }
        });
    }
}
    public class ProfileViewHolder extends MainViewHolder{
        TextView tv_name, login;
        ImageView iv_profile;

        public ProfileViewHolder(View v){
            super(v);
            this.tv_name = (TextView) v.findViewById(R.id.tv_profile);
            this.iv_profile = (ImageView) v.findViewById(R.id.iv_profile);
            this.login = (TextView) v.findViewById(R.id.tv_login);
        }
    }

    public void trace(String tag, String message){
        Log.d(tag , message);
    }
    public class MainViewHolder extends  RecyclerView.ViewHolder {
        public MainViewHolder(View v) {
            super(v);
        }
    }


}

disfruta !!!!

Yubaraj Poudel
fuente
Mi Viewholder1 tiene un diseño llamado myLaout1.xml y tiene ScrollView en él. Entonces, cuando desplazo esto, se desplaza la vista de reciclaje. Cómo desplazarse por el contenido de
Viewholder1
3

Podemos lograr una vista múltiple en RecyclerView único desde abajo: -

Dependencias en Gradle, así que agregue el siguiente código: -

compile 'com.android.support:cardview-v7:23.0.1'
compile 'com.android.support:recyclerview-v7:23.0.1'

RecyclerView en XML

<android.support.v7.widget.RecyclerView
    android:id="@+id/recyclerView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>

Código de actividad

private RecyclerView mRecyclerView;
private CustomAdapter mAdapter;
private RecyclerView.LayoutManager mLayoutManager;
private String[] mDataset = {“Data - one ”, Data - two”,
    Showing data three”, Showing data four”};
private int mDatasetTypes[] = {DataOne, DataTwo, DataThree}; //view types
 
...
 
mRecyclerView = (RecyclerView) findViewById(R.id.recyclerView);
mLayoutManager = new LinearLayoutManager(MainActivity.this);
mRecyclerView.setLayoutManager(mLayoutManager);
//Adapter is created in the last step
mAdapter = new CustomAdapter(mDataset, mDataSetTypes);
mRecyclerView.setAdapter(mAdapter);

Primer XML

<?xml version="1.0" encoding="utf-8"?>
<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:id="@+id/cardview"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/ten"
    android:elevation="@dimen/hundered”
    card_view:cardBackgroundColor=“@color/black“>
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding=“@dimen/ten">
 
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=“Fisrt”
            android:textColor=“@color/white“ />
 
        <TextView
            android:id="@+id/temp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/ten"
            android:textColor="@color/white"
            android:textSize="30sp" />
    </LinearLayout>
 
</android.support.v7.widget.CardView>

Segundo XML

<?xml version="1.0" encoding="utf-8"?>
<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:id="@+id/cardview"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/ten"
    android:elevation="100dp"
    card_view:cardBackgroundColor="#00bcd4">
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="@dimen/ten">
 
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=“DataTwo”
            android:textColor="@color/white" />
 
        <TextView
            android:id="@+id/score"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/ten"
            android:textColor="#ffffff"
            android:textSize="30sp" />
    </LinearLayout>
 
</android.support.v7.widget.CardView>

Tercer XML

<?xml version="1.0" encoding="utf-8"?>
<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:id="@+id/cardview"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginTop="@dimen/ten"
    android:elevation="100dp"
    card_view:cardBackgroundColor="@color/white">
 
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:padding="@dimen/ten">
 
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=“DataThree” />
 
        <TextView
            android:id="@+id/headline"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/ten"
            android:textSize="25sp" />
 
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="@dimen/ten"
            android:id="@+id/read_more"
            android:background="@color/white"
            android:text=“Show More/>
    </LinearLayout>
 
</android.support.v7.widget.CardView>

Ahora es el momento de hacer el adaptador y esto es principal para mostrar una vista -2 diferente en la misma vista del reciclador, así que compruebe este código completamente: -

public class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
    private static final String TAG = "CustomAdapter";
 
    private String[] mDataSet;
    private int[] mDataSetTypes;
 
    public static final int dataOne = 0;
    public static final int dataTwo = 1;
    public static final int dataThree = 2;
 
 
    public static class ViewHolder extends RecyclerView.ViewHolder {
        public ViewHolder(View v) {
            super(v);
        }
    }
 
    public class DataOne extends ViewHolder {
        TextView temp;
 
        public DataOne(View v) {
            super(v);
            this.temp = (TextView) v.findViewById(R.id.temp);
        }
    }
 
    public class DataTwo extends ViewHolder {
        TextView score;
 
        public DataTwo(View v) {
            super(v);
            this.score = (TextView) v.findViewById(R.id.score);
        }
    }
 
    public class DataThree extends ViewHolder {
        TextView headline;
        Button read_more;
 
        public DataThree(View v) {
            super(v);
            this.headline = (TextView) v.findViewById(R.id.headline);
            this.read_more = (Button) v.findViewById(R.id.read_more);
        }
    }
 
 
    public CustomAdapter(String[] dataSet, int[] dataSetTypes) {
        mDataSet = dataSet;
        mDataSetTypes = dataSetTypes;
    }
 
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
        View v;
        if (viewType == dataOne) {
            v = LayoutInflater.from(viewGroup.getContext())
                    .inflate(R.layout.weather_card, viewGroup, false);
 
            return new DataOne(v);
        } else if (viewType == dataTwo) {
            v = LayoutInflater.from(viewGroup.getContext())
                    .inflate(R.layout.news_card, viewGroup, false);
            return new DataThree(v);
        } else {
            v = LayoutInflater.from(viewGroup.getContext())
                    .inflate(R.layout.score_card, viewGroup, false);
            return new DataTwo(v);
        }
    }
 
    @Override
    public void onBindViewHolder(ViewHolder viewHolder, final int position) {
        if (viewHolder.getItemViewType() == dataOne) {
            DataOne holder = (DataOne) viewHolder;
            holder.temp.setText(mDataSet[position]);
        }
        else if (viewHolder.getItemViewType() == dataTwo) {
            DataThree holder = (DataTwo) viewHolder;
            holder.headline.setText(mDataSet[position]);
        }
        else {
            DataTwo holder = (DataTwo) viewHolder;
            holder.score.setText(mDataSet[position]);
        }
    }
 
    @Override
    public int getItemCount() {
        return mDataSet.length;
    }
 
   @Override
    public int getItemViewType(int position) {
        return mDataSetTypes[position];
    }
}

Puede consultar también este enlace para obtener más información.

duggu
fuente
pero eso funciona bien, pero cuando me desplazo rápido de arriba a abajo y viceversa obtengo un resultado extraño ... significa que los datos no están configurados correctamente. cual es su solucion
Rjz Satvara
2

Tienes que implementar el getItemViewType()método en RecyclerView.Adapter. Por defecto, la onCreateViewHolder(ViewGroup parent, int viewType)implementación viewTypede este método devuelve 0. En primer lugar, necesita ver el tipo de elemento en la posición a los efectos de ver el reciclaje y para eso debe anular el getItemViewType()método en el que puede pasar, viewTypelo que devolverá su posición del elemento. Código de ejemplo se da a continuación

@Override
public MyViewholder onCreateViewHolder(ViewGroup parent, int viewType) {
    int listViewItemType = getItemViewType(viewType);
    switch (listViewItemType) {
         case 0: return new ViewHolder0(...);
         case 2: return new ViewHolder2(...);
    }
}

@Override
public int getItemViewType(int position) {   
    return position;
}

// and in the similar way you can set data according 
// to view holder position by passing position in getItemViewType
@Override
public void onBindViewHolder(MyViewholder viewholder, int position) {
    int listViewItemType = getItemViewType(position);
    // ...
}
Amandeep Rohila
fuente
2

getItemViewType (int position) es la clave

En mi opinión, el punto de partida para crear este tipo de recyclerView es el conocimiento de este método. Dado que este método es opcional para anular, por lo tanto, no es visible en la clase RecylerView de forma predeterminada, lo que a su vez hace que muchos desarrolladores (incluido yo) se pregunten por dónde comenzar. Una vez que sepa que este método existe, crear tal RecyclerView sería un juego de niños.

ingrese la descripción de la imagen aquí

Cómo hacerlo ?

Puede crear una RecyclerViewcon cualquier cantidad de Vistas diferentes (ViewHolders). Pero para una mejor legibilidad tomemos un ejemplo de RecyclerViewcon dos Viewholders.
Recuerde estos 3 simples pasos y estará listo para comenzar.

  • Anular public int getItemViewType(int position)
  • Devuelve diferentes ViewHolders basados ​​en el ViewTypemétodo inCreateViewHolder ()
  • Vista de poblado basada en el onBindViewHolder()método itemViewType

    Aquí hay un fragmento de código para ti

    public class YourListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
    
        private static final int LAYOUT_ONE= 0;
        private static final int LAYOUT_TWO= 1;
    
        @Override
        public int getItemViewType(int position)
        {
            if(position==0)
               return LAYOUT_ONE;
            else
               return LAYOUT_TWO;
        }
    
        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    
            View view =null;
            RecyclerView.ViewHolder viewHolder = null;
    
            if(viewType==LAYOUT_ONE)
            {
               view = LayoutInflater.from(parent.getContext()).inflate(R.layout.one,parent,false);
               viewHolder = new ViewHolderOne(view);
            }
            else
            {
               view = LayoutInflater.from(parent.getContext()).inflate(R.layout.two,parent,false);
               viewHolder= new ViewHolderTwo(view);
            }
    
            return viewHolder;
        }
    
        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
    
           if(holder.getItemViewType()== LAYOUT_ONE)
           {
               // Typecast Viewholder 
               // Set Viewholder properties 
               // Add any click listener if any 
           }
           else {
    
               ViewHolderOne vaultItemHolder = (ViewHolderOne) holder;
               vaultItemHolder.name.setText(displayText);
               vaultItemHolder.name.setOnClickListener(new View.OnClickListener() {
                   @Override
                   public void onClick(View v) {
                       .......
                   }
               });
    
           }
    
       }
    
       /****************  VIEW HOLDER 1 ******************//
    
       public class ViewHolderOne extends RecyclerView.ViewHolder {
    
           public TextView name;
    
           public ViewHolderOne(View itemView) {
           super(itemView);
           name = (TextView)itemView.findViewById(R.id.displayName);
           }
       }
    
    
      //****************  VIEW HOLDER 2 ******************//
    
      public class ViewHolderTwo extends RecyclerView.ViewHolder{
    
           public ViewHolderTwo(View itemView) {
           super(itemView);
    
               ..... Do something
           }
      }
    }

Código GitHub:

Aquí hay un proyecto donde he implementado un RecyclerView con múltiples ViewHolders.

Rohit Singh
fuente
¿Qué pasa con lo mismo pero también con múltiples conjuntos de datos?
esQmo_
¿Qué quieres decir? @esQmo_
Rohit Singh
Quiero decir, ¿qué pasa si cada usuario tiene también un conjunto de datos diferente (fuente de datos)?
esQmo_
1

Simplemente puede devolver ItemViewType y usarlo. Ver el código a continuación:

@Override
public int getItemViewType(int position) {

    Message item = messageList.get(position);
    // return my message layout
    if(item.getUsername() == Message.userEnum.I)
        return R.layout.item_message_me;
    else
        return R.layout.item_message; // return other message layout
}

@Override
public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int viewType) {
    View view = LayoutInflater.from(viewGroup.getContext()).inflate(viewType, viewGroup, false);
    return new ViewHolder(view);
}
김영호
fuente
1

Puede usar la biblioteca: https://github.com/vivchar/RendererRecyclerViewAdapter

mRecyclerViewAdapter = new RendererRecyclerViewAdapter(); /* included from library */
mRecyclerViewAdapter.registerRenderer(new SomeViewRenderer(SomeModel.TYPE, this));
mRecyclerViewAdapter.registerRenderer(...); /* you can use several types of cells */

Para cada elemento, debe implementar un ViewRenderer, ViewHolder, SomeModel:

ViewHolder: es un titular de vista simple de vista de reciclador.

SomeModel: es su modelo con ItemModelinterfaz

public class SomeViewRenderer extends ViewRenderer<SomeModel, SomeViewHolder> {

    public SomeViewRenderer(final int type, final Context context) {
        super(type, context);
    }

    @Override
    public void bindView(@NonNull final SomeModel model, @NonNull final SomeViewHolder holder) {
       holder.mTitle.setText(model.getTitle());
    }

    @NonNull
    @Override
    public SomeViewHolder createViewHolder(@Nullable final ViewGroup parent) {
        return new SomeViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.some_item, parent, false));
    }
}

Para más detalles puedes mirar documentaciones.

Vitalia
fuente
0

Puede usar esta biblioteca:
https://github.com/kmfish/MultiTypeListViewAdapter (escrito por mí)

  • Mejor reutilice el código de una celda
  • Mejor expansión
  • Mejor desacoplamiento

Adaptador de instalación:

adapter = new BaseRecyclerAdapter();
adapter.registerDataAndItem(TextModel.class, LineListItem1.class);
adapter.registerDataAndItem(ImageModel.class, LineListItem2.class);
adapter.registerDataAndItem(AbsModel.class, AbsLineItem.class);

Para cada línea de pedido:

public class LineListItem1 extends BaseListItem<TextModel, LineListItem1.OnItem1ClickListener> {

    TextView tvName;
    TextView tvDesc;


    @Override
    public int onGetLayoutRes() {
        return R.layout.list_item1;
    }

    @Override
    public void bindViews(View convertView) {
        Log.d("item1", "bindViews:" + convertView);
        tvName = (TextView) convertView.findViewById(R.id.text_name);
        tvDesc = (TextView) convertView.findViewById(R.id.text_desc);

        tvName.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != attachInfo) {
                    attachInfo.onNameClick(getData());
                }
            }
        });
        tvDesc.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (null != attachInfo) {
                    attachInfo.onDescClick(getData());
                }
            }
        });

    }

    @Override
    public void updateView(TextModel model, int pos) {
        if (null != model) {
            Log.d("item1", "updateView model:" + model + "pos:" + pos);
            tvName.setText(model.getName());
            tvDesc.setText(model.getDesc());
        }
    }

    public interface OnItem1ClickListener {
        void onNameClick(TextModel model);
        void onDescClick(TextModel model);
    }
}
kmfish
fuente