Recyclerview und Umgang mit verschiedenen Arten der Zeileninflation

124

Ich versuche mit dem neuen zu arbeiten RecyclerView, aber ich konnte kein Beispiel dafür finden, dass RecyclerViewverschiedene Arten von Zeilen / Kartenansichten aufgeblasen werden.

Mit ListViewüberschreibe ich das getViewTypeCountund getItemViewType, um verschiedene Arten von Zeilen zu behandeln.

Soll ich es wie "alt" machen oder soll ich etwas damit machen LayoutManager? Ich fragte mich, ob mich jemand in die richtige Richtung weisen könnte. Weil ich nur Beispiele mit einem Typ finden kann.

Ich möchte eine Liste mit etwas anderen Karten haben. Oder sollte ich einfach ein scrollViewmit cardViewsinnen verwenden ... mach es ohne den Adapter und recyclerView?

Lokkio
quelle
Was ist der Unterschied zwischen Ihren Artikeltypen? Wie soll das Recyclerview auf verschiedene Typen reagieren? Im Allgemeinen gibt es nichts, was Sie mit einer Bildlauf- / Listenansicht tun können, was Sie mit einer Recyclingansicht nicht tun können, aber nicht umgekehrt
Gil Moshayof
Es ist tatsächlich so, wie Sie es im Google Play Store sehen. Oben können Sie eine Kopfzeile haben, dann sehen Sie drei Karten, dann haben Sie einen Abschnitt mit Informationen. Wird dies in einer Recycling-Ansicht / Listenansicht durchgeführt? Oder Bildlaufansicht? Denn wenn es eine Bildlaufansicht ist, muss ich vorher alle Layouts bestimmen. Mit einer Listenansicht kann ich einfach bestimmte Objekte zu meinem Datensatz hinzufügen und das richtige Layout wird aufgeblasen. Ich möchte wissen, wie der letzte Teil mit der neuen Recyclerview ausgeführt wird. Muss ich Methoden wie die Listenansicht überschreiben?
Lokkio
AnyOne sucht nach einer Github-Demo für das Layout mehrerer Zeilen mit dem Recycler code2concept.blogspot.in/2015/10/…
nitesh
Überprüfen Sie diesen Link, es wird für Sie funktionieren: - stackoverflow.com/a/39972276/3946958
Ravindra Kushwaha

Antworten:

202

Die Behandlung der Zeilen- / Abschnittslogik ähnlich der von UITableView in iOS ist in Android nicht so einfach wie in iOS. Wenn Sie jedoch RecyclerView verwenden, ist die Flexibilität Ihrer Möglichkeiten weitaus größer.

Am Ende geht es darum, wie Sie herausfinden, welche Art von Ansicht Sie im Adapter anzeigen. Sobald Sie das herausgefunden haben, sollte es einfach sein zu segeln (nicht wirklich, aber zumindest haben Sie das sortiert).

Der Adapter stellt zwei Methoden zur Verfügung, die Sie überschreiben sollten:

getItemViewType(int position)

Die Standardimplementierung dieser Methode gibt immer 0 zurück, was darauf hinweist, dass es nur einen Ansichtstyp gibt. In Ihrem Fall ist dies nicht der Fall, und Sie müssen einen Weg finden, um festzustellen, welche Zeile welchem ​​Ansichtstyp entspricht. Im Gegensatz zu iOS, das dies mit Zeilen und Abschnitten für Sie verwaltet, haben Sie hier nur einen Index, auf den Sie sich verlassen können, und Sie müssen Ihre Entwicklerfähigkeiten einsetzen, um zu wissen, wann eine Position mit einem Abschnittskopf korreliert und wann sie korreliert eine normale Reihe.

createViewHolder(ViewGroup parent, int viewType)

Sie müssen diese Methode trotzdem überschreiben, aber normalerweise ignorieren die Benutzer einfach den Parameter viewType. Je nach Ansichtstyp müssen Sie die richtige Layoutressource aufblasen und Ihren Ansichtshalter entsprechend erstellen. Die RecyclerView behandelt das Recycling verschiedener Ansichtstypen so, dass Konflikte zwischen verschiedenen Ansichtstypen vermieden werden.

Wenn Sie einen Standard-LayoutManager verwenden möchten, z. B. LinearLayoutManager, sollten Sie bereit sein. Wenn Sie planen, Ihre eigene LayoutManager-Implementierung zu erstellen, müssen Sie etwas härter arbeiten. Die einzige API, mit der Sie wirklich arbeiten müssen, findViewByPosition(int position)gibt eine bestimmte Ansicht an einer bestimmten Position. Da Sie es wahrscheinlich je nach Typ dieser Ansicht unterschiedlich gestalten möchten , haben Sie einige Möglichkeiten:

  1. Wenn Sie das ViewHolder-Muster verwenden, legen Sie normalerweise das Tag der Ansicht mit dem Ansichtshalter fest. Sie können dies zur Laufzeit im Layout-Manager verwenden, um herauszufinden, um welchen Typ es sich bei der Ansicht handelt, indem Sie im Ansichtshalter ein Feld hinzufügen, das dies ausdrückt.

  2. Da Sie eine Funktion benötigen, die bestimmt, welche Position mit welchem ​​Ansichtstyp korreliert, können Sie diese Methode auch irgendwie global zugänglich machen (möglicherweise eine Singleton-Klasse, die die Daten verwaltet?), Und dann können Sie einfach dieselbe Methode entsprechend abfragen die Position.

Hier ist ein Codebeispiel:

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

Hier ist ein Beispiel, wie diese Ansichtshalter aussehen sollten:

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

In diesem Beispiel wird natürlich davon ausgegangen, dass Sie Ihre Datenquelle (myData) so erstellt haben, dass die Implementierung eines Adapters auf diese Weise einfach ist. Als Beispiel zeige ich Ihnen, wie ich eine Datenquelle erstellen würde, die eine Liste mit Namen und eine Kopfzeile für jedes Mal enthält, wenn sich der erste Buchstabe des Namens ändert (vorausgesetzt, die Liste ist alphabetisch sortiert) - ähnlich wie bei Kontakten Liste würde aussehen wie:

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

Dieses Beispiel löst ein ziemlich spezifisches Problem, aber ich hoffe, dies gibt Ihnen einen guten Überblick über den Umgang mit verschiedenen Zeilentypen in einem Recycler und ermöglicht es Ihnen, die erforderlichen Anpassungen in Ihrem eigenen Code vorzunehmen, um Ihren Anforderungen zu entsprechen.

Gil Moshayof
quelle
Ziemlich toll, und ich denke, dies ist ein großartiges Beispiel für die Lösung eines solchen Problems. Beispiellösung
Amt87
Ein weiteres Beispiel für das Infalting der verschiedenen Zeilen in der Recycling-Ansicht ist: - stackoverflow.com/a/39972276/3946958
Ravindra Kushwaha
Sollte seinnames[i].substring(0, 1)
Kyle
1
Für Recycler-Ansichten mit heterogenen Elementen empfiehlt es sich, sich auch SpanSizeLookup anzusehen. stackoverflow.com/questions/26869312/…
Mahori
Es ist nützlich. Basierend auf dieser Antwort habe ich auch die Idee, die Mehrtypansicht in Adapter mithilfe von enum zu implementieren. Die Aufzählung enthält eine Methode onCreateViewHolder, mit der wir einen Ansichtshalter erstellen können. Für weitere Informationen
quangson91
114

Der Trick besteht darin, Unterklassen von ViewHolder zu erstellen und diese dann umzuwandeln.

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;  

Und dann machen Sie zur Laufzeit so etwas:

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

Ich hoffe es hilft.

Ticofab
quelle
3
Dies ist die direkte Antwort auf die Frage. Der einzige fehlende Teil ist die Notwendigkeit, onCreateViewHolder (ViewGroup-Eltern, int viewType) zu überschreiben und verschiedene Ansichtstypen basierend auf viewType zu behandeln
user1928896
Ein weiteres Beispiel für das Infalting der verschiedenen Zeilen in der Recycling-Ansicht ist: - stackoverflow.com/questions/39971350/…
Ravindra Kushwaha
1
Gibt es eine generische Lösung, anstatt die Basis des Ansichtshalters auf die Werte der Schaltergehäuse zu stützen?
Vahid Ghadiri
33

Laut Gil großartige Antwort, die ich durch Überschreiben des getItemViewType gelöst habe, wie von Gil erklärt. Seine Antwort ist großartig und muss als richtig markiert werden. In jedem Fall füge ich den Code hinzu, um die Punktzahl zu erreichen:

In Ihrem Recycler-Adapter:

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

Auf diese Weise können Sie jedes benutzerdefinierte Layout für jede Zeile festlegen!

iGio90
quelle
18
Nur ein kleiner Kommentar: Der zweite Parameter in onCreateViewHolder sollte der viewType sein, nicht der Index. Laut API: developer.android.com/reference/android/support/v7/widget/… , int)
Mark Martinsson
Aber was ist, wenn der Benutzer in diesem Moment schnell scrollt und eine seltsame Ausgabe erhält?
Rjz Satvara
15

Es ist ziemlich knifflig, aber so schwer, kopieren Sie einfach den folgenden Code und Sie sind fertig

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


}

genießen !!!!

Yubaraj Poudel
quelle
Mein Viewholder1 hat das Layout myLaout1.xml und ScrollView. Wenn ich dieses Ding scrolle, wird die Recycling-Ansicht gescrollt. So scrollen Sie durch den Inhalt von
Viewholder1
3

Wir können mehrere Ansichten auf einer einzelnen RecyclerView von unten erreichen: -

Abhängigkeiten von Gradle, fügen Sie also den folgenden Code hinzu: -

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

RecyclerView in XML

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

Aktivitätscode

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

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

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

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

Jetzt ist es an der Zeit, einen Adapter zu erstellen. Dies ist wichtig, um unterschiedliche -2-Ansichten in derselben Recycler-Ansicht anzuzeigen. Überprüfen Sie daher diesen Code-Fokus vollständig: -

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

Sie können auch diesen Link für weitere Informationen überprüfen .

Duggu
quelle
aber das funktioniert gut, aber wenn ich schnell von oben nach unten scrolle und umgekehrt, bekomme ich eine seltsame Ausgabe ... bedeutet, dass die Daten nicht richtig eingestellt sind. Was ist ihre Lösung?
Rjz Satvara
2

Sie müssen die getItemViewType()Methode in implementieren RecyclerView.Adapter. Standardmäßig wird die onCreateViewHolder(ViewGroup parent, int viewType)Implementierung viewTypedieser Methode zurückgegeben 0. Zunächst benötigen Sie den Ansichtstyp des Artikels an der Position zum Zwecke des Ansichtsrecyclings. Dazu müssen Sie die getItemViewType()Methode überschreiben , mit der Sie übergeben können, viewTypewodurch Ihre Position des Artikels zurückgegeben wird. Das Codebeispiel ist unten angegeben

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

getItemViewType (int position) ist der Schlüssel

Meiner Meinung nach ist der Ausgangspunkt für die Erstellung dieser Art von recyclerView das Wissen über diese Methode. Da diese Methode optional überschrieben werden kann, ist sie in der RecylerView-Klasse standardmäßig nicht sichtbar, was wiederum viele Entwickler (einschließlich mich) dazu veranlasst, sich zu fragen, wo sie anfangen sollen. Sobald Sie wissen, dass diese Methode vorhanden ist, wäre das Erstellen einer solchen RecyclerView ein Kinderspiel.

Geben Sie hier die Bildbeschreibung ein

Wie es geht ?

Sie können eine RecyclerViewmit beliebig vielen verschiedenen Ansichten (ViewHolders) erstellen. Nehmen wir zur besseren Lesbarkeit ein Beispiel RecyclerViewmit zwei Viewholders.
Denken Sie an diese 3 einfachen Schritte und Sie können loslegen.

  • Öffentliche int überschreiben getItemViewType(int position)
  • Geben Sie verschiedene ViewHolders basierend auf der ViewTypein onCreateViewHolder () -Methode zurück
  • Füllen Sie die Ansicht basierend auf der onBindViewHolder()Methode itemViewType in

    Hier ist ein Code-Snippet für Sie

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

GitHub-Code:

Hier ist ein Projekt, in dem ich eine RecyclerView mit mehreren ViewHoldern implementiert habe.

Rohit Singh
quelle
Was ist mit dem gleichen, aber auch mit mehreren Datensätzen?
esQmo_
Was meinst du? @esQmo_
Rohit Singh
Ich meine, was ist, wenn jeder Vieholder auch einen anderen Datensatz (Datenquelle) hat?
esQmo_
1

Sie können ItemViewType einfach zurückgeben und verwenden. Siehe folgenden Code:

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

Sie können die Bibliothek verwenden: 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 */

Für jedes Element sollten Sie einen ViewRenderer, ViewHolder, SomeModel implementieren:

ViewHolder - Es ist ein einfacher Ansichtshalter für die Recycler-Ansicht.

SomeModel - es ist Ihr Modell mit ItemModelSchnittstelle

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

Weitere Informationen finden Sie in den Dokumentationen.

Vitaly
quelle
0

Sie können diese Bibliothek verwenden:
https://github.com/kmfish/MultiTypeListViewAdapter (von mir geschrieben)

  • Verwenden Sie den Code einer Zelle besser wieder
  • Bessere Expansion
  • Bessere Entkopplung

Setup-Adapter:

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

Für jede Werbebuchung:

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