1062 Stimmen

Wie man RecyclerView mit mehreren Ansichtstypen erstellt

Von Erstellen von dynamischen Listen mit RecyclerView:

Wenn wir einen RecyclerView.Adapter erstellen, müssen wir einen ViewHolder angeben, der sich mit dem Adapter verbindet.

public class MyAdapter extends RecyclerView.Adapter {

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

Ist es möglich, einen RecyclerView mit mehreren Ansichtstypen zu erstellen?

7voto

Tulsi Punkte 699

Es ist sehr einfach und unkompliziert.

Überschreiben Sie einfach die getItemViewType() Methode in Ihrem Adapter. Anhand der Daten verschiedene itemViewType-Werte zurückgeben. Zum Beispiel, nehmen wir ein Objekt vom Typ Person mit einem Member isMale, wenn isMale true ist, dann 1 zurückgeben und wenn isMale false ist, dann 2 in der getItemViewType() Methode.

Nun kommen wir zur createViewHolder (ViewGroup parent, int viewType), anhand des viewType verschiedenen layout-Datei aufblasen. Wie folgt:

 if (viewType == 1){
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.male, parent, false);
    return new AdapterMaleViewHolder(view);
}
else{
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.female, parent, false);
    return new AdapterFemaleViewHolder(view);
}

in onBindViewHolder (VH holder,int position) prüfen, ob holder eine Instanz von AdapterFemaleViewHolder oder AdapterMaleViewHolder ist mit instanceof und entsprechend die Werte zuweisen.

Der ViewHolder könnte so aussehen

    class AdapterMaleViewHolder extends RecyclerView.ViewHolder {
            ...
            public AdapterMaleViewHolder(View itemView){
            ...
            }
        }

    class AdapterFemaleViewHolder extends RecyclerView.ViewHolder {
         ...
         public AdapterFemaleViewHolder(View itemView){
            ...
         }
    }

5voto

Dmitrii Bychkov Punkte 879

Ich empfehle diese Bibliothek von Hannes Dorfmann. Sie kapselt alle Logik bezüglich eines bestimmten Ansichtstyps in einem separaten Objekt namens "AdapterDelegate".

https://github.com/sockeqwe/AdapterDelegates

public class CatAdapterDelegate extends AdapterDelegate> {

  private LayoutInflater inflater;

  public CatAdapterDelegate(Activity activity) {
    inflater = activity.getLayoutInflater();
  }

  @Override public boolean isForViewType(@NonNull List items, int position) {
    return items.get(position) instanceof Cat;
  }

  @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
    return new CatViewHolder(inflater.inflate(R.layout.item_cat, parent, false));
  }

  @Override public void onBindViewHolder(@NonNull List items, int position,
      @NonNull RecyclerView.ViewHolder holder, @Nullable List payloads) {

    CatViewHolder vh = (CatViewHolder) holder;
    Cat cat = (Cat) items.get(position);

    vh.name.setText(cat.getName());
  }

  static class CatViewHolder extends RecyclerView.ViewHolder {

    public TextView name;

    public CatViewHolder(View itemView) {
      super(itemView);
      name = (TextView) itemView.findViewById(R.id.name);
    }
  }
}

public class AnimalAdapter extends ListDelegationAdapter> {

  public AnimalAdapter(Activity activity, List items) {

    // DelegatesManager ist ein geschütztes Feld in ListDelegationAdapter
    delegatesManager.addDelegate(new CatAdapterDelegate(activity))
                    .addDelegate(new DogAdapterDelegate(activity))
                    .addDelegate(new GeckoAdapterDelegate(activity))
                    .addDelegate(23, new SnakeAdapterDelegate(activity));

    // Setze die Elemente der Superklasse.
    setItems(items);
  }
}

4voto

ibrahimyilmaz Punkte 17433

Ich empfehle Ihnen zunächst, Hannes Dorfmanns großartigen Artikel zu diesem Thema zu lesen.

Wenn ein neuer Ansichtstyp hinzukommt, müssen Sie Ihren Adapter bearbeiten und so viele chaotische Dinge handhaben. Ihr Adapter sollte für Erweiterungen offen sein, aber für Änderungen geschlossen.

Sie können diese beiden Projekte überprüfen, um eine Vorstellung davon zu bekommen, wie man verschiedene ViewTypes im Adapter handhaben kann:

3voto

Mariusz Brona Punkte 1549

Wenn jemand interessiert ist, die super einfache Lösung in Kotlin zu sehen, überprüfen Sie den Blogbeitrag, den ich gerade erstellt habe. Das Beispiel im Blogbeitrag basiert auf der Erstellung von Sectioned RecyclerView:

https://brona.blog/2020/06/sectioned-recyclerview-in-three-steps/

2voto

Avinash Ch Punkte 76

Sie können mit mehreren Ansichtstypen RecyclerAdapter umgehen, indem Sie getItemViewType() den erwarteten viewType-Wert für diese Position zurückgeben lassen.

Ich habe einen MultipleViewTypeAdapter vorbereitet, um eine MCQ-Liste für Prüfungen zu erstellen, bei der eine Frage gestellt werden kann, die zwei oder mehr gültige Antworten (Checkbox-Optionen) und eine Frage mit einer einzelnen Antwort (Radiobutton-Optionen) haben kann.

Dafür erhalte ich den Fragetyp aus der API-Antwort und verwende ihn, um zu entscheiden, welche Ansicht ich für diese Frage anzeigen muss.

public class MultiViewTypeAdapter extends RecyclerView.Adapter {

    Context mContext;
    ArrayList dataSet;
    ArrayList questions;
    private Object radiobuttontype1;

    //Viewholder, um Fragen mit Kontrollkästchen anzuzeigen
    public static class Checkboxtype2 extends RecyclerView.ViewHolder {
        ImageView imgclockcheck;
        CheckBox checkbox;

        public Checkboxtype2(@NonNull View itemView) {
            super(itemView);
            imgclockcheck = (ImageView) itemView.findViewById(R.id.clockout_cbox_image);
            checkbox = (CheckBox) itemView.findViewById(R.id.clockout_cbox);
        }
    }

    //Viewholder, um Fragen mit Radiobuttons anzuzeigen

    public static class Radiobuttontype1 extends RecyclerView.ViewHolder {
        ImageView clockout_imageradiobutton;
        RadioButton clockout_radiobutton;
        TextView sample;

        public radiobuttontype1(View itemView) {
            super(itemView);
            clockout_imageradiobutton = (ImageView) itemView.findViewById(R.id.clockout_imageradiobutton);
            clockout_radiobutton = (RadioButton) itemView.findViewById(R.id.clockout_radiobutton);
            sample = (TextView) itemView.findViewById(R.id.sample);
        }
    }

    public MultiViewTypeAdapter(ArrayList data, Context context) {
        this.dataSet = data;
        this.mContext = context;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int viewType) {
        if (viewType.equalsIgnoreCase("1")) {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.clockout_radio_list_row, viewGroup, false);
            return new radiobuttontype1(view);

        } else if (viewType.equalsIgnoreCase("2")) {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.clockout_cbox_list_row, viewGroup, false);
            view.setHorizontalFadingEdgeEnabled(true);
            return new Checkboxtype2(view);

        } else if (viewType.equalsIgnoreCase("3")) {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.clockout_radio_list_row, viewGroup, false);
            return new Radiobuttontype1(view);

        } else if (viewType.equalsIgnoreCase("4")) {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.clockout_radio_list_row, viewGroup, false);
            return new Radiobuttontype1(view);

        } else if (viewType.equalsIgnoreCase("5")) {
            View view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.clockout_radio_list_row, viewGroup, false);
            return new Radiobuttontype1(view);
        }

        return null;
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int viewType) {
        if (viewType.equalsIgnoreCase("1")) {
            options =  dataSet.get(i).getOptions();
            question = dataSet.get(i).getQuestion();
            image = options.get(i).getValue();
            ((radiobuttontype1) viewHolder).clockout_radiobutton.setChecked(false);
            ((radiobuttontype1) viewHolder).sample.setText(question);
            //Das Bild im ViewHolder-View laden
            Picasso.with(mContext)
                    .load(image)
                    .into(((radiobuttontype1) viewHolder).clockout_imageradiobutton);

        } else if (viewType.equalsIgnoreCase("2")) {
            options = (ArrayList) dataSet.get(i).getOptions();
            question = dataSet.get(i).getQuestion();
            image = options.get(i).getValue();
            //Das Bild im ViewHolder-View laden
            Picasso.with(mContext)
                    .load(image)
                    .into(((Checkboxtype2) viewHolder).imgclockcheck);

        } else if (viewType.equalsIgnoreCase("3")) {
            //Daten für ViewHolder für Ansichtstyp 3 anpassen
        } else if (viewType.equalsIgnoreCase("4")) {
            //Daten für ViewHolder für Ansichtstyp 4 anpassen
        } else if (viewType.equalsIgnoreCase("5")) {
            //Daten für ViewHolder für Ansichtstyp 5 anpassen
        }
    }

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

    /**
     * Gibt den Ansichtstyp für diese Position zurück, indem der Ansichtstypwert aus dem
     *     Datensatz ausgewählt wird
     */
    @Override
    public int getItemViewType(int position) {
        return dataSet.get(position).getViewType();
    }
}

Sie können mehrfache bedingte Anweisungen basierend auf der viewHolder-Datenfüllung in onBindViewHolder() vermeiden, indem Sie ähnlichen Ansichten über ViewHolders, die sich in ihrer Positionierung unterscheiden, dieselben IDs zuweisen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X