Reciclerview e manipulação de diferentes tipos de inflação de linhas

124

Estou tentando trabalhar com o novo RecyclerView, mas não consegui encontrar um exemplo de um RecyclerViewcom diferentes tipos de linhas / visualizações de cartões sendo infladas.

Com ListViewI substituir o getViewTypeCounte getItemViewType, para lidar com diferentes tipos de linhas.

Devo fazê-lo da maneira "antiga" ou devo fazer alguma coisa LayoutManager? Fiquei me perguntando se alguém poderia me indicar a direção certa. Porque só consigo encontrar exemplos com um tipo.

Quero ter uma lista de cartões ligeiramente diferentes. Ou devo apenas usar um scrollViewcom cardViewsdentro dele ... torná-lo sem o adaptador e recyclerView?

Lokkio
fonte
qual é a diferença entre seus tipos de item? como a visão de reciclagem deve reagir a diferentes tipos? Em geral, não há nada que você pode fazer com um scrollview / listview que você não pode fazer com o um recyclerview, mas não o contrário
Gil Moshayof
Na verdade, é como o que você vê na loja do Google Play. No topo, você pode ter um cabeçalho, ver três cartas e uma seção com informações. Isso é feito em uma recyclerview / listview? Ou scrollview? Porque se for uma visualização de rolagem, preciso determinar todos os layouts antes. Com uma listview, posso adicionar certos objetos ao meu conjunto de dados e o layout correto será inflado. Então, eu quero saber, como fazer a última parte com a nova Recyclerview, preciso substituir métodos como o listview?
Lokkio 19/09/14
Quem procura github demonstração para o layout de várias linhas usando reciclador code2concept.blogspot.in/2015/10/...
nitesh
Possível duplicata de Como criar RecyclerView com vários tipos de exibição?
Ashok Varma 03/03
Verifique estes links, será viável para você: - stackoverflow.com/a/39972276/3946958
Ravindra Kushwaha

Respostas:

202

Lidar com a lógica de linhas / seções semelhante ao UITableView do iOS não é tão simples no Android quanto no iOS, no entanto, quando você usa o RecyclerView - a flexibilidade do que você pode fazer é muito maior.

No final, é tudo sobre como você descobre que tipo de exibição está exibindo no adaptador. Depois que você descobrir isso, deve ser fácil navegar (não realmente, mas pelo menos você terá isso resolvido).

O adaptador expõe dois métodos que você deve substituir:

getItemViewType(int position)

A implementação padrão desse método sempre retornará 0, indicando que há apenas 1 tipo de visualização. No seu caso, não é assim e, portanto, você precisará encontrar uma maneira de afirmar qual linha corresponde a qual tipo de visualização. Ao contrário do iOS, que gerencia isso para você com linhas e seções, aqui você terá apenas um índice em que confiar e precisará usar suas habilidades de desenvolvedor para saber quando uma posição se correlaciona com um cabeçalho de seção e quando se correlaciona com uma linha normal.

createViewHolder(ViewGroup parent, int viewType)

Você precisa substituir esse método de qualquer maneira, mas geralmente as pessoas simplesmente ignoram o parâmetro viewType. De acordo com o tipo de exibição, você precisará aumentar o recurso de layout correto e criar seu suporte de exibição de acordo. O RecyclerView lidará com a reciclagem de diferentes tipos de vistas, de forma a evitar conflitos de diferentes tipos de vistas.

Se você planeja usar um LayoutManager padrão, como LinearLayoutManagervocê deve estar pronto. Se você planeja criar sua própria implementação do LayoutManager, precisará trabalhar um pouco mais. A única API com a qual você realmente precisa trabalhar é a findViewByPosition(int position)que fornece uma determinada visualização em uma determinada posição. Como você provavelmente deseja definir de maneira diferente, dependendo do tipo dessa visualização, você tem algumas opções:

  1. Geralmente, ao usar o padrão ViewHolder, você define a etiqueta da vista com o suporte da vista. Você pode usar isso durante o tempo de execução no gerenciador de layout para descobrir que tipo de visualização é adicionando um campo no suporte da visualização que expressa isso.

  2. Como você precisará de uma função que determine qual posição se correlaciona a qual tipo de exibição, você também pode tornar esse método acessível globalmente de alguma forma (talvez uma classe singleton que gerencia os dados?) E, em seguida, você pode simplesmente consultar o mesmo método de acordo com a posição.

Aqui está um exemplo 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;
    }
}

Aqui está uma amostra de como esses detentores de exibição devem se parecer:

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());
    }    
}

Obviamente, este exemplo assume que você construiu sua fonte de dados (myData) de uma maneira que facilita a implementação de um adaptador dessa maneira. Como exemplo, mostrarei como construir uma fonte de dados que mostre uma lista de nomes e um cabeçalho para cada vez que a primeira letra do nome for alterada (suponha que a lista esteja em ordem alfabética) - semelhante à maneira como os contatos lista ficaria assim:

// 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 exemplo vem para resolver um problema bastante específico, mas espero que isso lhe dê uma boa visão geral sobre como lidar com diferentes tipos de linhas em uma recicladora e permita que você faça as adaptações necessárias em seu próprio código para atender às suas necessidades.

Gil Moshayof
fonte
Bastante impressionante, e acho que essa é uma ótima amostra para resolver esse problema. Sample Solution
Amt87 13/16
Outro exemplo para infalting as diferentes linhas dentro do recyelview que é: - stackoverflow.com/a/39972276/3946958
Ravindra Kushwaha
Deve sernames[i].substring(0, 1)
Kyle
1
Além disso, para visualizações de recicladores com itens heterogêneos, é uma boa ideia consultar o SpanSizeLookup também. stackoverflow.com/questions/26869312/…
Mahori
É útil. Baseando-me nesta resposta, também tenho uma idéia para implementar a exibição de vários tipos no Adapter usando enum. A enum terá um método onCreateViewHolderque nos ajudará a criar o detentor da visualização. Para mais detalhes você pode querer verificar a minha parte: stackoverflow.com/questions/47245398/...
quangson91
114

O truque é criar subclasses do ViewHolder e depois convertê-las.

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;  

E então, em tempo de execução, faça algo assim:

@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 que ajude.

ticofab
fonte
3
Esta é a resposta direta à pergunta. A única parte que falta é a necessidade de substituir onCreateViewHolder (pai do ViewGroup, int viewType) e manipular diferentes tipos de exibição com base no viewType
user1928896
Outro exemplo para infaltar as diferentes linhas dentro da recyelview que é: - stackoverflow.com/questions/39971350/…
Ravindra Kushwaha
1
Existe alguma solução genérica em vez de lançar a base do suporte da vista nos valores das caixas de comutação?
Vahid Ghadiri
33

De acordo com a grande resposta de Gil, resolvi substituindo o getItemViewType, conforme explicado por Gil. Sua resposta é ótima e precisa ser marcada como correta. De qualquer forma, adiciono o código para alcançar a pontuação:

No seu 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));
}

Ao fazer isso, você pode definir qualquer layout personalizado para qualquer linha!

iGio90
fonte
18
Apenas um pequeno comentário: o segundo parâmetro no onCreateViewHolder deve ser o viewType, não o índice. De acordo com a API: developer.android.com/reference/android/support/v7/widget/… , int)
Mark Martinsson
mas e quando o usuário rola rapidamente naquele momento alguma saída estranha que estou recebendo?
Rjz Satvara
15

É bastante complicado, mas muito difícil, basta copiar o código abaixo e pronto

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);
        }
    }


}

desfrutar !!!!

yubaraj poudel
fonte
Meu Viewholder1 possui um layout chamado myLaout1.xml e possui ScrollView. Então agora, quando eu rolar essa coisa, a recyclerview é rolada. Como rolar o conteúdo de
Viewholder1
3

Podemos obter várias visualizações no RecyclerView único a partir do caminho abaixo: -

Dependências do Gradle, adicione o código abaixo: -

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

RecyclerView em XML

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

Código da atividade

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);

Primeiro 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>

Terceiro 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>

Agora é hora de fazer o adaptador, e isso é importante para mostrar diferentes vistas -2 na mesma exibição do reciclador, portanto, verifique este foco do 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];
    }
}

Você também pode verificar este link para obter mais informações.

duggu
fonte
mas isso funciona bem, mas quando estou rolando rápido de cima para baixo e vice-versa, estou obtendo uma saída estranha ... significa que os dados não estão definidos corretamente. qual é a sua solução?
Rjz Satvara
2

Você precisa implementar o getItemViewType()método RecyclerView.Adapter. Por padrão, a onCreateViewHolder(ViewGroup parent, int viewType)implementação viewTypedesse método retorna 0. Primeiramente, é necessário visualizar o tipo do item na posição para fins de visualização da reciclagem e para isso é necessário substituir o getItemViewType()método pelo qual você pode passar, o viewTypeque retornará sua posição do item. A amostra de código é fornecida abaixo

@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
fonte
2

getItemViewType (int position) é a chave

Na minha opinião, o ponto de partida para criar esse tipo de recyclerView é o conhecimento desse método. Como esse método é opcional para substituir, portanto, não é visível na classe RecylerView por padrão, o que, por sua vez, faz com que muitos desenvolvedores (inclusive eu) se perguntem por onde começar. Depois que você souber que esse método existe, criar esse RecyclerView seria uma tarefa difícil.

insira a descrição da imagem aqui

Como fazer isso ?

Você pode criar um RecyclerViewcom qualquer número de modos de exibição diferentes (ViewHolders). Mas, para melhor legibilidade, vamos dar um exemplo RecyclerViewcom dois Viewholders.
Lembre-se destes 3 passos simples e você estará pronto para prosseguir.

  • Substituir int público getItemViewType(int position)
  • Retorne diferentes ViewHolders com base no ViewTypemétodo in onCreateViewHolder ()
  • Preencher Visualização com base no itemViewType no onBindViewHolder()método

    Aqui está um trecho de código para você

    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:

Aqui está um projeto em que implementei um RecyclerView com vários ViewHolders.

Rohit Singh
fonte
E o mesmo, mas também com vários conjuntos de dados?
esQmo_
O que você quer dizer? @esQmo_
Rohit Singh
Quero dizer, e se cada participante também tiver um conjunto de dados diferente (fonte de dados)?
esQmo_ 31/08/19
1

Você pode simplesmente retornar ItemViewType e usá-lo. Veja o código abaixo:

@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);
}
김영호
fonte
1

Você pode usar a 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 item, você deve implementar um ViewRenderer, ViewHolder, SomeModel:

ViewHolder - é um suporte simples para a visão do reciclador.

SomeModel - é o seu modelo com ItemModelinterface

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 mais detalhes, você pode procurar documentações.

Vitaly
fonte
0

Você pode usar esta biblioteca:
https://github.com/kmfish/MultiTypeListViewAdapter (escrito por mim)

  • Melhor reutilizar o código de uma célula
  • Melhor expansão
  • Melhor dissociação

Adaptador de instalação:

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

Para cada item de linha:

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
fonte