Recyclerview dan menangani berbagai jenis inflasi baris

124

Saya mencoba untuk bekerja dengan yang baru RecyclerView, tetapi saya tidak dapat menemukan contoh RecyclerViewdengan berbagai jenis baris / tampilan kartu yang meningkat.

Dengan ListViewsaya menimpa getViewTypeCountdan getItemViewType, untuk menangani berbagai jenis baris.

Apakah saya seharusnya melakukannya dengan cara "lama" atau haruskah saya melakukan sesuatu dengannya LayoutManager? Saya bertanya-tanya apakah seseorang bisa mengarahkan saya ke arah yang benar. Karena saya hanya dapat menemukan contoh dengan satu jenis.

Saya ingin memiliki daftar kartu yang sedikit berbeda. Atau haruskah saya hanya menggunakan scrollViewdengan cardViewsdi dalamnya ... membuatnya tanpa adaptor dan recyclerView?

Lokkio
sumber
apa perbedaan antara jenis barang Anda? bagaimana seharusnya recyclerview bereaksi terhadap berbagai jenis? Secara umum, tidak ada yang dapat Anda lakukan dengan scrollview / listview yang tidak dapat Anda lakukan dengan recyclerview, tetapi tidak sebaliknya
Gil Moshayof
Ini sebenarnya seperti apa yang Anda lihat di google play store. Di bagian atas Anda dapat memiliki header, lalu Anda dapat melihat tiga kartu, lalu Anda memiliki bagian dengan info. Apakah ini dilakukan dalam recyclerview / listview? Atau scrollview? Karena jika ini adalah scrollview, saya perlu menentukan semua layout sebelumnya. Dengan listview saya hanya bisa menambahkan objek tertentu ke dataset saya dan tata letak yang tepat akan meningkat. Jadi saya ingin tahu, bagaimana melakukan bagian terakhir dengan Recyclerview baru, apakah saya perlu mengganti metode seperti listview?
Lokkio
Siapa saja yang mencari demo github untuk tata letak beberapa baris menggunakan recycler code2concept.blogspot.in/2015/10/…
nitesh
Kemungkinan duplikat dari Cara membuat RecyclerView dengan beberapa jenis tampilan?
Ashok Varma
Periksa tautan ini, ini akan bisa Anda gunakan: - stackoverflow.com/a/39972276/3946958
Ravindra Kushwaha

Jawaban:

202

Menangani logika baris / bagian yang mirip dengan UITableView di iOS tidak sesederhana di Android seperti di iOS, namun, ketika Anda menggunakan RecyclerView - fleksibilitas yang dapat Anda lakukan jauh lebih besar.

Pada akhirnya, ini semua tentang bagaimana Anda mengetahui jenis tampilan yang Anda tampilkan di Adaptor. Setelah Anda mengetahuinya, itu harus mudah berlayar (tidak juga, tapi setidaknya Anda akan memiliki yang diurutkan).

Adaptor memaparkan dua metode yang harus Anda timpa:

getItemViewType(int position)

Implementasi default metode ini akan selalu menghasilkan 0, menunjukkan bahwa hanya ada 1 jenis tampilan. Dalam kasus Anda, tidak demikian halnya, dan Anda perlu menemukan cara untuk menegaskan baris mana yang sesuai dengan tipe tampilan mana. Tidak seperti iOS, yang mengelola ini untuk Anda dengan baris dan bagian, di sini Anda hanya akan memiliki satu indeks untuk diandalkan, dan Anda harus menggunakan keterampilan pengembang Anda untuk mengetahui kapan posisi berkorelasi dengan header bagian, dan kapan itu berkorelasi dengan baris normal.

createViewHolder(ViewGroup parent, int viewType)

Anda perlu mengganti metode ini, tetapi biasanya orang mengabaikan parameter viewType. Menurut jenis tampilan, Anda harus mengembang sumber daya tata letak yang benar dan membuat pemegang tampilan Anda sesuai. RecyclerView akan menangani daur ulang berbagai jenis tampilan dengan cara yang menghindari bentrok dari berbagai jenis tampilan.

Jika Anda berencana menggunakan LayoutManager default, seperti LinearLayoutManager, Anda sebaiknya melakukannya. Jika Anda berencana membuat implementasi LayoutManager Anda sendiri, Anda harus bekerja sedikit lebih keras. Satu-satunya API yang benar-benar harus Anda kerjakan adalah findViewByPosition(int position)yang memberikan tampilan tertentu pada posisi tertentu. Karena Anda mungkin ingin meletakkannya secara berbeda tergantung pada jenis tampilan ini, Anda memiliki beberapa opsi:

  1. Biasanya saat menggunakan pola ViewHolder, Anda mengatur tag view dengan view view. Anda bisa menggunakan ini selama runtime di manajer tata letak untuk mengetahui apa jenis tampilan dengan menambahkan bidang di tempat tampilan yang mengekspresikan ini.

  2. Karena Anda akan memerlukan fungsi yang menentukan posisi mana yang berkorelasi dengan tipe tampilan mana, Anda mungkin juga membuat metode ini dapat diakses secara global (mungkin kelas tunggal yang mengelola data?), Dan kemudian Anda dapat dengan mudah menanyakan metode yang sama sesuai dengan Posisinya.

Berikut ini contoh kode:

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

Berikut ini contoh tampilan pemegang tampilan:

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

Tentu saja, sampel ini mengasumsikan Anda telah membangun sumber data Anda (myData) dengan cara yang membuatnya mudah untuk mengimplementasikan adaptor dengan cara ini. Sebagai contoh, saya akan menunjukkan kepada Anda bagaimana saya akan membangun sumber data yang menunjukkan daftar nama, dan header untuk setiap kali huruf pertama dari nama tersebut berubah (anggaplah daftar itu disusun menurut abjad) - mirip dengan cara kontak daftar akan terlihat seperti:

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

Contoh ini datang untuk menyelesaikan masalah yang cukup spesifik, tetapi saya harap ini memberi Anda tinjauan yang baik tentang bagaimana menangani jenis baris yang berbeda dalam pendaur ulang, dan memungkinkan Anda membuat adaptasi yang diperlukan dalam kode Anda sendiri agar sesuai dengan kebutuhan Anda.

Gil Moshayof
sumber
Cukup menakjubkan, dan saya pikir ini adalah contoh yang bagus untuk memecahkan masalah seperti itu. Contoh Solusi
Amt87
Contoh lain untuk membuat berbagai baris yang berbeda di dalam recyelview yaitu: - stackoverflow.com/a/39972276/3946958
Ravindra Kushwaha
Seharusnyanames[i].substring(0, 1)
Kyle
1
Selain itu, untuk tampilan pendaur ulang dengan item heterogen, sebaiknya lihat juga SpanSizeLookup. stackoverflow.com/questions/26869312/…
Mahori
Ini bermanfaat. Berdasarkan jawaban ini saya juga punya ide untuk mengimplementasikan tampilan multi-tipe di Adaptor dengan menggunakan enum. Enum akan memiliki metode onCreateViewHolderyang membantu kami membuat view view. Untuk detail lebih lanjut Anda mungkin ingin memeriksa bagian saya: stackoverflow.com/questions/47245398/…
quangson91
114

Caranya adalah dengan membuat subclass dari ViewHolder dan kemudian melemparkannya.

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;  

Dan kemudian, saat runtime lakukan sesuatu seperti ini:

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

Semoga ini bisa membantu.

tokofab
sumber
3
Ini adalah jawaban langsung untuk pertanyaan. Satu-satunya bagian yang hilang adalah kebutuhan untuk menimpa onCreateViewHolder (induk ViewGroup, int viewType) dan menangani berbagai jenis tampilan berdasarkan tipe tampilan
user1928896
Contoh lain untuk membuat berbagai baris yang berbeda di dalam recyelview yaitu: - stackoverflow.com/questions/39971350/…
Ravindra Kushwaha
1
Apakah ada solusi generik alih-alih casting basis pemegang tampilan pada nilai kasus sakelar?
Vahid Ghadiri
33

Menurut Gil jawaban hebat yang saya pecahkan dengan Mengganti getItemViewType seperti yang dijelaskan oleh Gil. Jawabannya bagus dan harus ditandai sebagai benar. Bagaimanapun, saya menambahkan kode untuk mencapai skor:

Di adaptor pendaur ulang Anda:

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

Dengan melakukan ini, Anda dapat mengatur tata letak khusus apa pun untuk baris apa pun!

iGio90
sumber
18
Hanya komentar kecil: Parameter kedua di onCreateViewHolder haruslah viewType, bukan indeks. Menurut API: developer.android.com/reference/android/support/v7/widget/… , int)
Mark Martinsson
tetapi bagaimana ketika pengguna bergulir cepat pada saat itu beberapa output aneh yang saya dapatkan.
Rjz Satvara
15

Ini cukup rumit tetapi sulit, cukup salin kode di bawah ini dan Anda selesai

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


}

Nikmati !!!!

poudel yubaraj
sumber
Viewholder1 saya memiliki tata letak bernama myLaout1.xml dan memiliki ScrollView di dalamnya. Jadi sekarang ketika saya menggulir hal ini recyclerview akan digulir. Bagaimana cara menggulir konten
Viewholder1
3

Kami dapat mencapai beberapa tampilan pada RecyclerView tunggal dari cara berikut: -

Ketergantungan pada Gradle jadi tambahkan kode di bawah ini: -

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

RecyclerView dalam XML

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

Kode Kegiatan

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

XML pertama

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

XML kedua

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

XML ketiga

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

Sekarang saatnya membuat adaptor dan ini adalah utama untuk menampilkan tampilan -2 berbeda pada tampilan pendaur ulang yang sama jadi silakan periksa fokus kode ini sepenuhnya: -

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

Anda juga dapat memeriksa tautan ini untuk informasi lebih lanjut.

Duggu
sumber
tapi itu berfungsi dengan baik tetapi ketika saya menggulir cepat dari atas ke bawah dan sebaliknya saya mendapatkan beberapa output aneh ... berarti data tidak diatur dengan benar,. apa solusinya?
Rjz Satvara
2

Anda harus menerapkan getItemViewType()metode dalam RecyclerView.Adapter. Secara default onCreateViewHolder(ViewGroup parent, int viewType)implementasi viewTypemetode ini kembali 0. Pertama, Anda perlu melihat jenis item pada posisi untuk keperluan daur ulang tampilan dan untuk itu Anda harus mengganti getItemViewType()metode yang dapat Anda lewati viewTypeyang akan mengembalikan posisi item Anda. Contoh kode diberikan di bawah ini

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

getItemViewType (posisi int) adalah kuncinya

Menurut pendapat saya, titik awal untuk membuat jenis recyclerView ini adalah pengetahuan tentang metode ini. Karena metode ini opsional untuk ditimpa oleh karena itu tidak terlihat di kelas RecylerView secara default yang pada gilirannya membuat banyak pengembang (termasuk saya) bertanya-tanya harus mulai dari mana. Setelah Anda mengetahui bahwa metode ini ada, membuat RecyclerView seperti itu akan menjadi cakewalk.

masukkan deskripsi gambar di sini

Bagaimana cara melakukannya ?

Anda dapat membuat RecyclerViewdengan sejumlah Tampilan yang berbeda (ViewHolders). Tetapi untuk keterbacaan yang lebih baik mari kita ambil contoh RecyclerViewdengan dua Viewholders.
Ingat 3 langkah sederhana ini dan Anda akan baik untuk pergi.

  • Override public int getItemViewType(int position)
  • Kembalikan ViewHolders yang berbeda berdasarkan pada metode ViewTypeonCreateViewHolder ()
  • Populate View berdasarkan pada itemViewType dalam onBindViewHolder()metode

    Ini cuplikan kode untuk Anda

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

Kode GitHub:

Ini adalah proyek di mana saya telah menerapkan RecyclerView dengan beberapa ViewHolders.

Rohit Singh
sumber
Bagaimana dengan yang sama tetapi juga memiliki beberapa set data?
esQmo_
Maksud kamu apa? @esQmo_
Rohit Singh
Maksud saya bagaimana jika setiap vieholder juga memiliki dataset yang berbeda (sumber data)?
esQmo_
1

Anda bisa mengembalikan ItemViewType dan menggunakannya. Lihat kode di bawah ini:

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

Anda dapat menggunakan perpustakaan: 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 */

Untuk setiap item, Anda harus menerapkan ViewRenderer, ViewHolder, SomeModel:

ViewHolder - ini adalah pemegang tampilan sederhana dari pendaur ulang.

SomeModel - ini adalah model Anda dengan ItemModelantarmuka

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

Untuk lebih jelasnya Anda bisa melihat dokumentasi.

Vitaly
sumber
0

Anda dapat menggunakan perpustakaan ini:
https://github.com/kmfish/MultiTypeListViewAdapter (ditulis oleh saya)

  • Lebih baik menggunakan kembali kode satu sel
  • Ekspansi yang lebih baik
  • Decoupling yang lebih baik

Adaptor pemasangan:

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

Untuk setiap item baris:

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
sumber