Recyclerview и обработка различных типов надувания строк

124

Я пытаюсь работать с новым RecyclerView, но мне не удалось найти пример RecyclerViewраздуваемых строк / карт разных типов.

С помощью ListViewя переопределяю getViewTypeCountи getItemViewTypeдля обработки различных типов строк.

Должен ли я делать это "по-старому" или надо что-то делать LayoutManager? Мне было интересно, может ли кто-нибудь указать мне правильное направление. Потому что я могу найти только примеры с одним типом.

Я хочу иметь список немного разных карточек. Или мне просто использовать scrollViewс cardViewsвнутри ... сделать это без адаптера и recyclerView?

Lokkio
источник
в чем разница между вашими типами предметов? как Reclerview должен реагировать на разные типы? В общем, вы ничего не можете сделать с scrollview / listview, чего нельзя сделать с recyclerview, но не наоборот
Гил Мошайоф
Это действительно похоже на то, что вы видите в магазине Google Play. Вверху у вас может быть заголовок, затем вы видите три карточки, затем у вас есть раздел с информацией. Это сделано в recyclerview / listview? Или прокрутка? Потому что, если это прокрутка, мне нужно заранее определить все макеты. С помощью списка я могу просто добавить определенные объекты в свой набор данных, и правильный макет будет увеличен. Итак, я хочу знать, как сделать последнюю часть с новым Recyclerview, нужно ли мне переопределить такие методы, как listview?
Локкио
AnyOne ищет демонстрацию на github для многострочного макета с использованием recycler 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) таким образом, чтобы упростить реализацию адаптера таким образом. В качестве примера я покажу вам, как я бы сконструировал источник данных, который показывает список имен и заголовок для каждого изменения 1-й буквы имени (предположим, что список составлен по алфавиту) - аналогично тому, как контакты список будет выглядеть так:

// 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,
Другой пример инфальтации различных строк внутри recyelview: - stackoverflow.com/a/39972276/3946958
Равиндра Кушваха
Должно бытьnames[i].substring(0, 1)
Кайл
1
Кроме того, для представлений ресайклера с разнородными элементами неплохо также взглянуть на SpanSizeLookup. stackoverflow.com/questions/26869312/…
Mahori
Это полезно. Основываясь на этом ответе, у меня также есть идея реализовать представление нескольких типов в адаптере с помощью 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;
    }
}

Надеюсь, поможет.

ticofab
источник
3
Это прямой ответ на вопрос. Единственная отсутствующая часть - необходимость переопределить onCreateViewHolder (родительский элемент ViewGroup, int viewType) и обрабатывать различные типы представлений на основе viewType
user1928896
Другой пример инфальтации различных строк внутри recyelview: stackoverflow.com/questions/39971350/…
Ravindra Kushwaha
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));
}

Таким образом вы можете установить любой пользовательский макет для любой строки!

iGio90
источник
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. Итак, теперь, когда я прокручиваю эту вещь, отображается recyclerview. Как прокручивать контент Viewholder1
Анкеш кумар Джайсансария
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 position) - это ключ

На мой взгляд, отправной точкой для создания такого типа recyclerView является знание этого метода. Поскольку этот метод необязательно переопределять, он не отображается в классе RecylerView по умолчанию, что, в свою очередь, заставляет многих разработчиков (включая меня) задуматься, с чего начать. Как только вы узнаете, что этот метод существует, создание такого RecyclerView будет легкой прогулкой.

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

Как это сделать ?

Вы можете создать объект RecyclerViewс любым количеством различных представлений (ViewHolders). Но для лучшей читаемости возьмем пример RecyclerViewс двумя Viewholders.
Запомните эти 3 простых шага, и все будет в порядке.

  • Переопределить общедоступное int getItemViewType(int position)
  • Возвращать разные ViewHolder на основе ViewTypeметода onCreateViewHolder ()
  • Заполнить представление на основе onBindViewHolder()метода itemViewType in

    Вот вам фрагмент кода

    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_
Рохит Сингх
Я имею в виду, что, если у каждого зрителя есть другой набор данных (источник данных)?
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);
    }
}
kmfish
источник