Cómo crear RecyclerView con múltiples tipos de vistas

Resuelto Pongpat asked hace 54 años • 23 respuestas

De Crear listas dinámicas con RecyclerView :

Cuando creamos un RecyclerView.Adaptertenemos que especificar ViewHolderque 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 RecyclerViewcon múltiples tipos de vistas?

Pongpat avatar Jan 01 '70 08:01 Pongpat
Aceptado

Si es posible. Simplemente implemente getItemViewType() y ocúpese del viewTypepará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;
        }
    }
}
Anton Savin avatar Oct 07 '2014 21:10 Anton Savin

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.

  1. getItemCount
    Devuelve el recuento total de elementos de DataBinders

  2. getItemViewType
    Define la lógica de mapeo entre la posición del adaptador y el tipo de vista.

  3. getDataBinder
    Devuelve la instancia de DataBinder según el tipo de vista

  4. getPosition
    Defina la lógica de conversión a la posición del adaptador desde la posición en el DataBinder especificado.

  5. 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.

yqritc avatar Apr 01 '2015 14:04 yqritc