Tái chế và xử lý các loại lạm phát hàng khác nhau


124

Tôi đang cố gắng làm việc với cái mới RecyclerView, nhưng tôi không thể tìm thấy một ví dụ về một RecyclerViewloại hàng / thẻ xem khác nhau bị thổi phồng.

Với ListViewtôi ghi đè getViewTypeCountgetItemViewType, để xử lý các loại hàng khác nhau.

Tôi có nên làm theo cách "cũ" hay tôi nên làm gì với LayoutManager? Tôi đã tự hỏi nếu ai đó có thể chỉ cho tôi đi đúng hướng. Bởi vì tôi chỉ có thể tìm thấy các ví dụ với một loại.

Tôi muốn có một danh sách các thẻ hơi khác nhau. Hoặc nên tôi chỉ sử dụng một scrollViewvới cardViewsbên trong của nó ... làm cho nó mà không có adapter và recyclerView?


sự khác biệt giữa các loại mặt hàng của bạn là gì? Recyclerview nên phản ứng thế nào với các loại khác nhau? Nói chung, bạn không thể làm gì với scrollview / listview mà bạn không thể làm với recyclerview, nhưng không phải là cách khác
Gil Moshayof

Nó thực sự giống như những gì bạn thấy trong cửa hàng google play. Ở đầu bạn có thể có một tiêu đề, sau đó bạn có thể thấy ba thẻ, sau đó bạn có một phần có thông tin. Điều này được thực hiện trong một recyclerview / listview? Hay cuộn? Bởi vì nếu đó là một scrollview, tôi cần xác định tất cả các bố cục trước đó. Với một listview tôi chỉ có thể thêm các đối tượng nhất định vào tập dữ liệu của mình và bố cục phù hợp sẽ được tăng cao. Vì vậy, tôi muốn biết, làm thế nào để thực hiện phần cuối cùng với Recyclerview mới, tôi có cần ghi đè các phương thức như listview không?
Lokkio

AnyOne đang tìm kiếm bản demo github cho bố cục nhiều hàng bằng cách sử dụng mã tái chế2concept.blogspot.in
2015/


Kiểm tra các liên kết này, nó sẽ hoạt động cho bạn: - stackoverflow.com/a/39972276/3946958
Ravindra Kushwaha

Câu trả lời:


202

Xử lý logic hàng / phần tương tự như UITableView của iOS không đơn giản trong Android như trong iOS, tuy nhiên, khi bạn sử dụng RecyclerView - tính linh hoạt của những gì bạn có thể làm còn lớn hơn nhiều.

Cuối cùng, tất cả là về cách bạn tìm ra loại chế độ xem nào bạn đang hiển thị trong Bộ điều hợp. Một khi bạn đã tìm ra điều đó, nó sẽ dễ dàng đi thuyền (không thực sự, nhưng ít nhất bạn sẽ có được sắp xếp đó).

Bộ điều hợp hiển thị hai phương thức mà bạn nên ghi đè:

getItemViewType(int position)

Việc triển khai mặc định của phương thức này sẽ luôn trả về 0, chỉ ra rằng chỉ có 1 kiểu xem. Trong trường hợp của bạn, nó không phải như vậy, và vì vậy bạn sẽ cần tìm cách để xác nhận hàng nào tương ứng với kiểu xem nào. Không giống như iOS, nơi quản lý điều này cho bạn với các hàng và phần, ở đây bạn sẽ chỉ có một chỉ mục để dựa vào và bạn sẽ cần sử dụng các kỹ năng dành cho nhà phát triển của mình để biết khi nào một vị trí tương quan với tiêu đề của phần và khi nào nó tương quan với một hàng bình thường.

createViewHolder(ViewGroup parent, int viewType)

Dù sao bạn cũng cần ghi đè phương thức này, nhưng thông thường mọi người chỉ bỏ qua tham số viewType. Theo loại chế độ xem, bạn sẽ cần tăng tài nguyên bố cục chính xác và tạo chủ sở hữu chế độ xem phù hợp. RecyclerView sẽ xử lý tái chế các loại chế độ xem khác nhau theo cách tránh sự xung đột của các loại chế độ xem khác nhau.

Nếu bạn đang dự định sử dụng Trình quản lý bố cục mặc định, chẳng hạn như LinearLayoutManager, bạn nên sử dụng. Nếu bạn đang lên kế hoạch thực hiện Bố cục Trình quản lý của riêng mình, bạn sẽ cần làm việc chăm chỉ hơn một chút. API duy nhất bạn thực sự phải làm việc là findViewByPosition(int position)cung cấp một chế độ xem nhất định tại một vị trí nhất định. Vì có thể bạn sẽ muốn bố trí nó khác nhau tùy thuộc vào loại chế độ xem này, bạn có một vài tùy chọn:

  1. Thông thường khi sử dụng mẫu ViewHolder, bạn đặt thẻ của chế độ xem với chủ sở hữu chế độ xem. Bạn có thể sử dụng điều này trong thời gian chạy trong trình quản lý bố cục để tìm hiểu kiểu xem là gì bằng cách thêm một trường trong trình giữ khung thể hiện điều này.

  2. Vì bạn sẽ cần một hàm xác định vị trí tương quan với kiểu xem nào, nên bạn cũng có thể làm cho phương thức này có thể truy cập toàn cầu bằng cách nào đó (có thể là một lớp đơn lẻ quản lý dữ liệu?), Và sau đó bạn có thể truy vấn cùng một phương thức theo vị trí.

Đây là một mẫu mã:

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

Đây là một ví dụ về cách những người giữ chế độ xem này sẽ trông như thế nào:

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

Tất nhiên, mẫu này giả định rằng bạn đã xây dựng nguồn dữ liệu của mình (myData) theo cách giúp dễ dàng thực hiện bộ điều hợp theo cách này. Ví dụ: tôi sẽ chỉ cho bạn cách tôi xây dựng nguồn dữ liệu hiển thị danh sách tên và tiêu đề cho mỗi lần chữ cái đầu tiên của tên thay đổi (giả sử danh sách được xếp theo thứ tự chữ cái) - tương tự như cách liên hệ danh sách sẽ như thế nào:

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

Ví dụ này để giải quyết một vấn đề khá cụ thể, nhưng tôi hy vọng điều này cung cấp cho bạn một cái nhìn tổng quan tốt về cách xử lý các loại hàng khác nhau trong trình tái chế và cho phép bạn thực hiện các điều chỉnh cần thiết trong mã của riêng mình để phù hợp với nhu cầu của bạn.


Khá tuyệt vời, và tôi nghĩ rằng đây là một mẫu tuyệt vời để giải quyết vấn đề như vậy Giải pháp mẫu
Amt87

Một ví dụ khác để đưa vào các hàng khác nhau trong recyelview đó là: - stackoverflow.com/a/39972276/3946958
Ravindra Kushwaha

Nên lànames[i].substring(0, 1)
Kyle

1
Ngoài ra, đối với các chế độ xem tái chế với các mục không đồng nhất, bạn cũng nên xem SpanSizeLookup. stackoverflow.com/questions/26869312/ Lời
Mahori

Nó rất hữu ích. Dựa trên câu trả lời này, tôi cũng có một ý tưởng để thực hiện chế độ xem nhiều loại trong Bộ điều hợp bằng cách sử dụng enum. Enum sẽ có phương thức onCreateViewHoldergiúp chúng ta tạo view view. Để biết thêm chi tiết, bạn có thể muốn kiểm tra chia sẻ của tôi: stackoverflow.com/questions/47245398/NH
quangson91

114

Mẹo nhỏ là tạo các lớp con của ViewHolder và sau đó bỏ chúng.

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;  

Và sau đó, tại thời gian chạy làm một cái gì đó như thế này:

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

Hy vọng nó giúp.


3
Đây là câu trả lời trực tiếp cho câu hỏi. Phần còn thiếu duy nhất là cần ghi đè onCreateViewHolder (cha mẹ của Viewgroup, int viewType) và xử lý các kiểu xem khác nhau dựa trên viewType
user1928896 17/2/2016

Một ví dụ khác để đưa vào các hàng khác nhau trong recyelview đó là: - stackoverflow.com/questions/39971350/ chủ
Ravindra Kushwaha

1
Có bất kỳ giải pháp chung chung nào thay vì truyền cơ sở giữ khung nhìn trên các giá trị trường hợp chuyển đổi không?
Vahid Ghadiri

33

Theo câu trả lời tuyệt vời của Gil, tôi đã giải quyết bằng cách ghi đè getItemViewType như được giải thích bởi Gil. Câu trả lời của ông là tuyệt vời và phải được đánh dấu là chính xác. Trong mọi trường hợp, tôi thêm mã để đạt được điểm:

Trong bộ chuyển đổi tái chế của bạn:

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

Bằng cách này, bạn có thể đặt bất kỳ bố cục tùy chỉnh cho bất kỳ hàng nào!


18
Chỉ là một nhận xét nhỏ: Tham số thứ hai trong onCreateViewHolder phải là viewType, không phải là chỉ mục. Theo API: developer.android.com/reference/android/support/v7/widget/ ,, int)
Mark Martinsson

Nhưng những gì về khi người dùng cuộn nhanh tại thời điểm đó một số đầu ra kỳ lạ tôi đang nhận được.
Rjz Satvara

15

Nó khá khó nhưng rất khó, chỉ cần sao chép đoạn mã dưới đây và bạn đã hoàn thành

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


}

thưởng thức !!!!


Viewholder1 của tôi có bố cục có tên myLaout1.xml và có ScrollView trong đó. Vì vậy, bây giờ khi tôi cuộn thứ này, recyclerview được cuộn. Cách cuộn nội dung của
Viewholder1

3

Chúng tôi có thể đạt được nhiều chế độ xem trên một RecyclerView từ bên dưới: -

Phụ thuộc vào Gradle để thêm mã dưới đây: -

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

RecyclerView trong XML

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

Mã hoạt động

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 đầu tiên

<?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 thứ hai

<?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 thứ ba

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

Bây giờ đã đến lúc tạo bộ điều hợp và đây là chính để hiển thị chế độ xem -2 khác nhau trên cùng một chế độ xem tái chế, vì vậy vui lòng kiểm tra tập trung mã này đầy đủ: -

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

Bạn cũng có thể kiểm tra liên kết này để biết thêm thông tin.


nhưng điều đó hoạt động tốt nhưng khi tôi cuộn nhanh từ trên xuống dưới và ngược lại tôi nhận được một số đầu ra kỳ lạ ... có nghĩa là dữ liệu không được đặt đúng. giải pháp của nó là gì?
Rjz Satvara

2

Bạn phải thực hiện getItemViewType()phương pháp trong RecyclerView.Adapter. Theo mặc định onCreateViewHolder(ViewGroup parent, int viewType)thực hiện viewTypephương thức này trả về 0. Trước tiên, bạn cần xem loại mục tại vị trí cho mục đích tái chế chế độ xem và bạn phải ghi đè getItemViewType()phương thức mà bạn có thể vượt qua viewTypeđể trả về vị trí của mục. Mẫu mã được đưa ra dưới đây

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

2

getItemViewType (vị trí int) là khóa

Theo tôi, điểm khởi đầu để tạo ra loại recyclerView này là kiến ​​thức về phương pháp này. Vì phương thức này là tùy chọn để ghi đè, do đó, nó không hiển thị trong lớp RecylerView theo mặc định, điều này khiến nhiều nhà phát triển (bao gồm cả tôi) tự hỏi nên bắt đầu từ đâu. Một khi bạn biết rằng phương pháp này tồn tại, việc tạo RecyclerView như vậy sẽ là một lối đi lại.

nhập mô tả hình ảnh ở đây

Làm thế nào để làm nó ?

Bạn có thể tạo một RecyclerViewsố lượng bất kỳ Chế độ xem khác nhau (ViewHolders). Nhưng để dễ đọc hơn, hãy lấy một ví dụ về RecyclerViewhai Viewholders.
Hãy nhớ 3 bước đơn giản này và bạn sẽ tốt để đi.

  • Ghi đè int int getItemViewType(int position)
  • Trả về các ViewHolders khác nhau dựa trên ViewTypephương thức onCreateViewHolder ()
  • Chế độ xem dân số dựa trên itemViewType trong onBindViewHolder()phương thức

    Đây là một đoạn mã cho bạn

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

Mã GitHub:

Đây là một dự án nơi tôi đã triển khai RecyclerView với nhiều ViewHolders.


Điều gì giống nhau nhưng cũng có nhiều bộ dữ liệu?
esQmo_

Ý anh là gì? @esQmo_
Rohit Singh

Ý tôi là sao nếu mỗi vieholder cũng có dữ liệu khác nhau (nguồn dữ liệu)?
esQmo_

1

Bạn chỉ có thể trả về ItemViewType và sử dụng nó. Xem mã dưới đây:

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

1

Bạn có thể sử dụng thư viện: https://github.com/vivchar/RendererRecyclerViewAdOG

mRecyclerViewAdapter = new RendererRecyclerViewAdapter(); /* included from library */
mRecyclerViewAdapter.registerRenderer(new SomeViewRenderer(SomeModel.TYPE, this));
mRecyclerViewAdapter.registerRenderer(...); /* you can use several types of cells */

Đối với mỗi mục, bạn nên triển khai ViewRenderer, ViewHolder, someModel:

ViewHolder - nó là một khung nhìn đơn giản của khung nhìn tái chế.

Một số mô hình - đó là mô hình của bạn với ItemModelgiao diện

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

Để biết thêm chi tiết bạn có thể xem tài liệu.


0

Bạn có thể sử dụng thư viện này:
https://github.com/kmfish/MultiTypeListViewAdOG (được viết bởi tôi)

  • Sử dụng tốt hơn mã của một ô
  • Mở rộng tốt hơn
  • Phân tách tốt hơn

Bộ điều hợp cài đặt:

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

Đối với từng mục hàng:

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);
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.