Recyclerview 和处理不同类型的行膨胀

Posted

技术标签:

【中文标题】Recyclerview 和处理不同类型的行膨胀【英文标题】:Recyclerview and handling different type of row inflation 【发布时间】:2014-11-12 20:57:03 【问题描述】:

我正在尝试使用新的 RecyclerView,但我找不到 RecyclerView 的示例,其中不同类型的行/卡片视图被夸大了。

对于ListView,我会覆盖getViewTypeCountgetItemViewType,以处理不同类型的行。

我应该像“旧”方式那样做,还是应该用LayoutManager 做点什么?我想知道是否有人可以指出我正确的方向。因为我只能找到一种类型的例子。

我想要一份略有不同的卡片列表。或者我应该只使用scrollViewcardViews 里面...让它没有适配器和recyclerView

【问题讨论】:

你们的项目类型有什么区别? recyclerview 应该如何应对不同的类型?一般来说,滚动视图/列表视图没有什么可以做的,而回收者视图则不能做,但反之则不行 它实际上就像您在 google play 商店中看到的一样。在顶部你可以有一个标题,然后你可以看到三张卡片,然后你有一个包含信息的部分。这是在回收站视图/列表视图中完成的吗?还是滚动视图?因为如果它是滚动视图,我需要先确定所有布局。使用列表视图,我可以将某些对象添加到我的数据集中,并且正确的布局将被夸大。所以我想知道,如何用新的Recyclerview做最后一部分,是否需要覆盖listview之类的方法? AnyOne 正在寻找使用回收器的多行布局的 github 演示 code2concept.blogspot.in/2015/10/… How to create RecyclerView with multiple view type?的可能重复 检查这些链接,它对你有用:- ***.com/a/39972276/3946958 【参考方案1】:

android 中处理类似于 ios 的 UITableView 的行/部分逻辑并不像在 iOS 中那么简单,但是,当您使用 RecyclerView 时 - 您可以做的事情的灵活性要大得多。

最后,关键在于您如何确定您在适配器中显示的视图类型。一旦你弄清楚了,它应该很容易航行(不是真的,但至少你会整理好)。

适配器公开了两个你应该重写的方法:

getItemViewType(int position)

这个方法的默认实现会一直返回0,表示只有1种视图。在您的情况下,情况并非如此,因此您需要找到一种方法来断言哪一行对应于哪种视图类型。与通过行和节为您管理的 iOS 不同,在这里您将只有一个索引可以依赖,并且您需要使用您的开发人员技能来了解位置何时与节标题相关,以及何时与一个正常的行。

createViewHolder(ViewGroup parent, int viewType)

无论如何你都需要重写这个方法,但通常人们只是忽略 viewType 参数。根据视图类型,您需要扩充正确的布局资源并相应地创建您的视图持有者。 RecyclerView 将以一种避免不同视图类型冲突的方式处理不同视图类型的回收。

如果您打算使用默认的 LayoutManager,例如 LinearLayoutManager,那么您应该很高兴。如果您打算制作自己的 LayoutManager 实现,则需要更加努力。您真正必须使用的唯一 API 是 findViewByPosition(int position),它在特定位置提供给定视图。由于您可能希望根据视图的type 对其进行不同的布局,因此您有以下几种选择:

    通常在使用 ViewHolder 模式时,您使用视图持有者设置视图的标签。您可以在运行时在布局管理器中使用它,通过在视图持有者中添加一个表达这一点的字段来找出视图的类型。

    1234563根据位置查询相同的方法。

这是一个代码示例:

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

此示例旨在解决一个相当具体的问题,但我希望这可以让您很好地了解如何在回收器中处理不同的行类型,并允许您在自己的代码中进行必要的调整以满足您的需求。

【讨论】:

非常棒,我认为这是解决此类问题的一个很好的示例Sample Solution 另一个在recyelview中插入不同行的例子是:-***.com/a/39972276/3946958 应该是names[i].substring(0, 1) 此外,对于具有异构项目的回收站视图,最好也查看 SpanSizeLookup。 ***.com/questions/26869312/… 很有用。基于这个答案,我还有一个想法,通过使用枚举在适配器中实现多类型视图。枚举将有方法 onCreateViewHolder 帮助我们创建视图持有者。更多细节你可能想查看我的分享:***.com/questions/47245398/…【参考方案2】:

诀窍是创建 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;
    

希望对你有帮助。

【讨论】:

这是问题的直接答案。唯一缺少的部分是需要重写 onCreateViewHolder(ViewGroup parent, int viewType) 并根据 viewType 处理不同的视图类型 另一个在recyelview中插入不同行的例子是:-***.com/questions/39971350/… 是否有任何通用解决方案,而不是基于 switch case 值投射视图持有者?【参考方案3】:

根据 Gil 的好答案,我通过覆盖 Gil 解释的 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));

通过这样做,您可以为任何行设置任何自定义布局!

【讨论】:

只是一个小评论:onCreateViewHolder 中的第二个参数应该是视图类型,而不是索引。根据 API:developer.android.com/reference/android/support/v7/widget/…, int) 但是当用户快速滚动时我得到了一些奇怪的输出。【参考方案4】:

这很棘手,但也很难,只需复制以下代码即可完成

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 的内容【参考方案5】:

我们可以通过以下方式在单个 RecyclerView 上实现多个视图:-

对 Gradle 的依赖,所以添加以下代码:-

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

XML 中的 RecyclerView

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

活动代码

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_
    android:layout_
    android:layout_marginTop="@dimen/ten"
    android:elevation="@dimen/hundered”
    card_view:cardBackgroundColor=“@color/black“>
 
    <LinearLayout
        android:layout_
        android:layout_
        android:orientation="vertical"
        android:padding=“@dimen/ten">
 
        <TextView
            android:layout_
            android:layout_
            android:text=“Fisrt”
            android:textColor=“@color/white“ />
 
        <TextView
            android:id="@+id/temp"
            android:layout_
            android:layout_
            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_
    android:layout_
    android:layout_marginTop="@dimen/ten"
    android:elevation="100dp"
    card_view:cardBackgroundColor="#00bcd4">
 
    <LinearLayout
        android:layout_
        android:layout_
        android:orientation="vertical"
        android:padding="@dimen/ten">
 
        <TextView
            android:layout_
            android:layout_
            android:text=“DataTwo”
            android:textColor="@color/white" />
 
        <TextView
            android:id="@+id/score"
            android:layout_
            android:layout_
            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_
    android:layout_
    android:layout_marginTop="@dimen/ten"
    android:elevation="100dp"
    card_view:cardBackgroundColor="@color/white">
 
    <LinearLayout
        android:layout_
        android:layout_
        android:orientation="vertical"
        android:padding="@dimen/ten">
 
        <TextView
            android:layout_
            android:layout_
            android:text=“DataThree” />
 
        <TextView
            android:id="@+id/headline"
            android:layout_
            android:layout_
            android:layout_marginTop="@dimen/ten"
            android:textSize="25sp" />
 
        <Button
            android:layout_
            android:layout_
            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];
    

您也可以查看link 了解更多信息。

【讨论】:

但这很好用,但是当我从上到下快速滚动时,反之亦然,我得到一些奇怪的输出......意味着数据设置不正确,。它的解决方案是什么?【参考方案6】:

getItemViewType(int position) 是关键

在我看来,创建这种recyclerView的出发点 是这个方法的知识。由于此方法是可选的 覆盖因此默认情况下它在 RecylerView 类中不可见 这反过来又让许多开发人员(包括我)想知道去哪里 开始。一旦你知道这个方法存在,创建这样的 RecyclerView 将是小菜一碟。

怎么做?

您可以创建一个RecyclerView,其中包含任意数量的不同视图(ViewHolders)。但是为了更好的可读性,让我们以RecyclerView 和两个Viewholders 为例。 记住这 3 个简单的步骤,一切顺利。

覆盖公共 int getItemViewType(int position) 根据ViewType in 返回不同的 ViewHolders onCreateViewHolder() 方法

根据onBindViewHolder()方法中的itemViewType填充View

这是给你的代码sn-p

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 代码:

这是一个project,我在其中实现了一个带有多个 ViewHolders 的 RecyclerView。

【讨论】:

相同但也有多个数据集呢? 什么意思? @esQmo_ 我的意思是如果每个观众也有不同的数据集(数据源)呢?【参考方案7】:

你必须在RecyclerView.Adapter 中实现getItemViewType() 方法。默认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);
    // ...

【讨论】:

【参考方案8】:

您可以只返回 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);

【讨论】:

【参考方案9】:

您可以使用该库: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));
    

有关更多详细信息,您可以查看文档。

【讨论】:

【参考方案10】:

你可以使用这个库: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);
    

【讨论】:

以上是关于Recyclerview 和处理不同类型的行膨胀的主要内容,如果未能解决你的问题,请参考以下文章

在RecyclerView中膨胀两种类型的.XML

如何根据其在 onCreateViewHolder 方法中的位置在 RecyclerView 中膨胀不同的布局

在 RecyclerView 上膨胀类 ImageView 时出错

Recyclerview - OnCreateViewholder - 在某些情况下如何返回“null”

回收视图膨胀不同的行:- 绑定数据时出现异常

在水平和垂直的recyclerview中膨胀布局,具有recycler视图的FlexboxLayout添加视图水平自动垂直