Переробка та переробка різних типів інфляції рядків


124

Я намагаюся працювати з новим RecyclerView, але мені не вдалося знайти приклад того, як RecyclerViewрізні види рядків / переглядів карт завищені.

За допомогою ListViewя переосмислюю getViewTypeCountі getItemViewTypeдля обробки різних типів рядків.

Чи повинен я робити це як "старий" спосіб чи мені щось робити LayoutManager? Мені було цікаво, чи хтось міг би вказати на мене в правильному напрямку. Тому що я можу знайти приклади лише одного типу.

Я хочу мати список трохи інших карток. Або я повинен просто використовувати scrollViewз cardViewsвсередині нього ... зробити це без адаптера і recyclerView?


Яка різниця між типами предметів? як має реагувати рециркулятор на різні типи? Взагалі, нічого не можна зробити із переглядом / переглядом списків, чого не можна зробити з переглядом рециркуляторів, але не навпаки
Гіль Мошайоф,

Це насправді схоже на те, що ви бачите в магазині Google Play. Угорі у вас може бути заголовок, потім видно три картки, потім у вас розділ з інформацією. Це робиться в перегляді / перегляді списку? Або прокрутка? Тому що якщо це прокрутка, мені потрібно визначити всі макети раніше. За допомогою перегляду списку я можу просто додати певні об'єкти до мого набору даних, і правильний макет буде завищений. Отже, я хочу знати, як зробити останню частину з новим Recyclerview, чи потрібно мені переосмислити такі методи, як listview?
Локкіо

Будь-хто шукає демонстрацію github для розмітки декількох рядків за допомогою рециркулятора code2concept.blogspot.in/2015/10/…
nitesh


Перевірте це посилання, воно буде корисним для вас: - stackoverflow.com/a/39972276/3946958
Равіндра Кушваха

Відповіді:


202

Обробка логіки рядків / розділів, схожа на UITableView iOS, не така проста в Android, як в iOS, однак, коли ви використовуєте RecyclerView - гнучкість того, що ви можете зробити, набагато більша.

Зрештою, все полягає в тому, як розібратися, який тип подання відображається в адаптері. Після того, як ви це зрозуміли, плавати слід легко (не дуже, але принаймні у вас буде це відсортовано).

Адаптер розкриває два способи, які слід перекрити:

getItemViewType(int position)

Реалізація цього методу за замовчуванням завжди повертатиме 0, що вказує на те, що існує лише 1 тип перегляду. У вашому випадку це не так, і вам знадобиться знайти спосіб стверджувати, який рядок відповідає якому типу перегляду. На відміну від iOS, який керує цим для вас за допомогою рядків і розділів, тут у вас буде лише один індекс, на який можна покластися, і вам потрібно буде використовувати свої навички розробника, щоб знати, коли позиція корелює з заголовком розділу та коли вона співвідноситься з звичайний ряд.

createViewHolder(ViewGroup parent, int viewType)

Цей спосіб у будь-якому разі потрібно замінити, але зазвичай люди просто ігнорують параметр viewType. Відповідно до типу перегляду, вам потрібно завищити правильний ресурс компонування та створити відповідний власник перегляду відповідно. RecyclerView обробляє переробку різних типів перегляду таким чином, щоб уникнути зіткнення різних типів перегляду.

Якщо ви плануєте використовувати програму LayoutManager за замовчуванням, наприклад LinearLayoutManager, вам слід погодитися . Якщо ви плануєте зробити власну реалізацію LayoutManager, вам доведеться попрацювати трохи важче. Єдиний API, з яким ви дійсно маєте працювати, - це findViewByPosition(int position)який дає заданий вигляд у певній позиції. Оскільки ви, мабуть, захочете викласти його по-різному, залежно від типу цього виду, у вас є кілька варіантів:

  1. Зазвичай, використовуючи шаблон ViewHolder, ви встановлюєте тег перегляду разом із власником перегляду. Ви можете використовувати це під час виконання роботи в диспетчері макетів, щоб дізнатися, який тип подання, додавши поле у ​​власнику подання, яке виражає це.

  2. Оскільки вам знадобиться функція, яка визначає, яка позиція корелює з типом перегляду, ви також можете зробити цей метод глобально доступним якось (можливо, однокласний клас, який управляє даними?), А потім ви можете просто запитати той самий метод відповідно до положення.

Ось зразок коду:

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

Ось зразок того, як повинні виглядати ці власники перегляду:

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

Звичайно, цей зразок передбачає, що ви сконструювали джерело даних (myData) таким чином, що таким чином полегшується реалізація адаптера. Як приклад, я покажу вам, як я побудував би джерело даних, яке відображає список імен та заголовок кожного разу, коли перша літера імені змінюється (припустимо, що список буквений) - аналогічно тому, як контакти список виглядатиме так:

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

Цей приклад вирішує досить конкретну проблему, але я сподіваюся, що це дає хороший огляд того, як обробляти різні типи рядків у переробнику, і дозволяє зробити необхідні адаптації у власному коді відповідно до ваших потреб.


Досить дивовижно, і я думаю, що це чудовий зразок для вирішення такої проблеми Зразок рішення
Amt87

Інший приклад для заповнення різних рядків всередині рецензії, а саме: - stackoverflow.com/a/39972276/3946958
Равіндра Кушваха

Має бутиnames[i].substring(0, 1)
Кайл

1
Крім того, для переглядів рециркулятора з неоднорідними елементами, також непогано також переглянути SpanSizeLookup. stackoverflow.com/questions/26869312 / ...
Mahori

Це корисно. Базуючись на цій відповіді, я також маю ідею реалізувати перегляд багатьох типів в Adapter, використовуючи enum. У enum буде метод, onCreateViewHolderякий допоможе нам створити власника перегляду. Для більш докладної інформації ви можете перевірити свою частку: stackoverflow.com/questions/47245398 / ...
quangson91

114

Хитрість полягає в тому, щоб створити підкласи ViewHolder і потім викласти їх.

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;  

А потім під час виконання виконайте щось подібне:

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

Сподіваюся, це допомагає.


3
Це пряма відповідь на питання. Єдина частина, яка відсутня - це необхідність переосмислити onCreateViewHolder (батьківський вигляд ViewGroup, int viewType) та обробити різні типи перегляду на основі viewType
user1928896

Інший приклад для заповнення різних рядків всередині рецензії, а саме: - stackoverflow.com/questions/39971350/…
Равіндра Кушваха,

1
Чи є якесь загальне рішення замість того, щоб лишити базу власника виду на значення корпусу комутатора?
Вахід Гадірі

33

Відповідно до відмінної відповіді Гіля, я вирішив переосмислення getItemViewType, як пояснив Гіл. Його відповідь є чудовою і її потрібно позначити як правильну. У будь-якому випадку я додаю код, щоб досягти рахунку:

У адаптері для переробки:

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

Роблячи це, ви можете встановити будь-який спеціальний макет для будь-якого рядка!


18
Лише незначний коментар: Другим параметром в onCreateViewHolder повинен бути viewType, а не індекс. Відповідно до API: developer.android.com/reference/android/support/v7/widget/… , int)
Марк Мартінсон

але що робити, коли користувач швидко прокручує в той момент якийсь дивний вихід, який я отримую.
Rjz Satvara

15

Це досить складно, але настільки важко, просто скопіюйте наведений нижче код і ви закінчите

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


}

насолоджуйтесь !!!!


Мій Viewholder1 має макет з назвою myLaout1.xml і в ньому є ScrollView. Тому тепер, коли я прокручую цю річ, рециркулятор прокручується. Як прокручувати вміст Viewholder1
Ankesh kumar Jaisansaria

3

Ми можемо досягти декількох переглядів на одному RecyclerView знизу: -

Залежності від Gradle, тому додайте нижче код: -

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

RecyclerView в XML

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

Код діяльності

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

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

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

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

Настав час зробити адаптер, і це головне для показу різного -2 виду на одному виду рециркулятора, тому, будь ласка, перевірте цей фокус коду повністю: -

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

Ви також можете перевірити це посилання для отримання додаткової інформації.


але це добре працює, але коли я швидко прокручую зверху вниз і навпаки, я отримую дивний вихід ... значить, дані не встановлені належним чином. яке його рішення?
Rjz Satvara

2

Ви повинні реалізувати getItemViewType()метод у RecyclerView.Adapter. За замовчуванням onCreateViewHolder(ViewGroup parent, int viewType)реалізація viewTypeцього методу повертається 0. По-перше, вам потрібен тип перегляду предмета в положенні для цілей перегляду перегляду, і для цього вам доведеться перекрити getItemViewType()метод, в якому ви зможете пройти, viewTypeякий поверне ваше положення товару. Зразок коду наведено нижче

@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 (позиція int) є ключовим

На мою думку, вихідним моментом для створення такого виду recilerlerView є знання цього методу. Оскільки цей метод необов'язковий для переосмислення, тому він не видно у класі RecylerView за замовчуванням, що, в свою чергу, змушує багатьох розробників (включаючи мене) задаватися питанням з чого почати. Як тільки ви дізнаєтесь, що цей метод існує, створення такого RecyclerView було б проходом.

введіть тут опис зображення

Як це зробити ?

Ви можете створити RecyclerViewбудь-яку кількість різних переглядів (ViewHolders). Але для кращої читабельності давайте приклад RecyclerViewз двома Viewholders.
Запам’ятайте ці 3 простих кроки, і вам буде добре піти.

  • Переоцінка загальнодоступної вставки getItemViewType(int position)
  • Повертайте різні ViewHolders на основі ViewTypeметоду inCreateViewHolder ()
  • Перегляд населення на основі onBindViewHolder()методу itemViewType

    Ось фрагмент коду для вас

    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:

Ось проект, де я реалізував RecyclerView з декількома ViewHolders.


Що про те саме, але маючи також безліч наборів даних?
esQmo_

Що ви маєте на увазі? @esQmo_
Rohit Singh

Я маю на увазі, що якщо кожен власник viehold також має різний набір даних (джерело даних)?
esQmo_

1

Ви можете просто повернути ItemViewType і використовувати його. Дивіться нижче код:

@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

Ви можете використовувати бібліотеку: 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 */

Для кожного елемента слід реалізувати ViewRenderer, ViewHolder, SomeModel:

ViewHolder - це простий власник подання перегляду рециркулятора.

SomeModel - це ваша модель з ItemModelінтерфейсом

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

Більш детально ви можете подивитися документацію.


0

Ви можете використовувати цю бібліотеку:
https://github.com/kmfish/MultiTypeListViewAdapter (написано мною)

  • Краще повторно використовувати код однієї комірки
  • Краще розширення
  • Краще роз’єднання

Адаптер налаштування:

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

Для кожної позиції:

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);
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.