Android Recyclerview 和处理不同类型的行膨胀
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25914003/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Recyclerview and handling different type of row inflation
提问by Lokkio
I'm trying to work with the new RecyclerView
, but I could not find an example of a RecyclerView
with different types of rows/cardviews getting inflated.
我正在尝试使用 new RecyclerView
,但找不到RecyclerView
不同类型的行/卡片视图膨胀的示例。
With ListView
I override the getViewTypeCount
and getItemViewType
, for handling different types of rows.
使用ListView
I 覆盖getViewTypeCount
和getItemViewType
,用于处理不同类型的行。
Am I supposed to do it like the "old" way or should I do something with LayoutManager
? I was wondering if someone could point me to the right direction. Because I can only find examples with one type.
我应该像“旧”方式那样做还是应该用它做点什么LayoutManager
?我想知道是否有人可以指出我正确的方向。因为我只能找到一种类型的例子。
I want to have a list of slightly different cards. Or should I just use a scrollView
with cardViews
inside of it...make it without the adapter and recyclerView
?
我想要一个略有不同的卡片列表。或者我应该只使用一个scrollView
与cardViews
它里面......度过,即使没有适配器和recyclerView
?
回答by Gil Moshayof
Handling the rows / sections logic similar to iOS's UITableView is not as simple in Android as it is in iOS, however, when you use RecyclerView - the flexibility of what you can do is far greater.
处理类似于 iOS 的 UITableView 的行/部分逻辑在 Android 中不像在 iOS 中那么简单,但是,当您使用 RecyclerView 时 - 您可以做的事情的灵活性要大得多。
In the end, it's all about how you figure out what type of view you're displaying in the Adapter. Once you got that figured out, it should be easy sailing (not really, but at least you'll have that sorted).
最后,这完全取决于您如何确定您在适配器中显示的视图类型。一旦你弄清楚了,它应该很容易航行(不是真的,但至少你会排序)。
The Adapter exposes two methods which you should override:
Adapter 公开了两个您应该覆盖的方法:
getItemViewType(int position)
This method's default implementation will always return 0, indicating that there is only 1 type of view. In your case, it is not so, and so you will need find a way to assert which row corresponds to which view type. Unlike iOS, which manages this for you with rows and sections, here you will have only one index to rely on, and you'll need to use your developer skills to know when a position correlates to a section header, and when it correlates to a normal row.
这个方法的默认实现总是返回0,表示只有1种视图。在您的情况下,情况并非如此,因此您需要找到一种方法来断言哪一行对应于哪个视图类型。与 iOS 不同,它通过行和节为你管理这个,在这里你将只有一个索引可以依赖,你需要使用你的开发技能来知道一个位置何时与节标题相关,何时与一个正常的行。
createViewHolder(ViewGroup parent, int viewType)
You need to override this method anyway, but usually people just ignore the viewType parameter. According to the view type, you'll need to inflate the correct layout resource and create your view holder accordingly. The RecyclerView will handle recycling different view types in a way which avoids clashing of different view types.
无论如何您都需要覆盖此方法,但通常人们只是忽略 viewType 参数。根据视图类型,您需要扩充正确的布局资源并相应地创建您的视图持有者。RecyclerView 将以一种避免不同视图类型冲突的方式处理回收不同的视图类型。
If you're planning on using a default LayoutManager, such as LinearLayoutManager
, you should be good to go. If you're planning on making your own LayoutManager implementation, you'll need to work a bit harder. The only API you really have to work with is findViewByPosition(int position)
which gives a given view at a certain position. Since you'll probably want to lay it out differently depending on what typethis view is, you have a few options:
如果您打算使用默认的 LayoutManager,例如LinearLayoutManager
,您应该很高兴。如果您打算制作自己的 LayoutManager 实现,则需要更努力地工作。您真正需要使用的唯一 API 是findViewByPosition(int position)
在特定位置提供给定视图。由于您可能希望根据此视图的类型对其进行不同的布局,因此您有几个选择:
Usually when using the ViewHolder pattern, you set the view's tag with the view holder. You could use this during runtime in the layout manager to find out what type the view is by adding a field in the view holder which expresses this.
Since you'll need a function which determines which position correlates to which view type, you might as well make this method globally accessible somehow (maybe a singleton class which manages the data?), and then you can simply query the same method according to the position.
通常在使用 ViewHolder 模式时,您使用视图持有者设置视图的标签。您可以在运行时在布局管理器中使用它,通过在视图持有者中添加一个表达这一点的字段来找出视图的类型。
由于您需要一个函数来确定哪个位置与哪个视图类型相关,您不妨以某种方式使该方法全局可访问(也许是管理数据的单例类?),然后您可以简单地根据位置。
Here's a code sample:
这是一个代码示例:
// 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;
}
}
Here's a sample of how these view holders should look like:
以下是这些视图持有者的示例:
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());
}
}
Of course, this sample assumes you've constructed your data source (myData) in a way that makes it easy to implement an adapter in this way. As an example, I'll show you how I'd construct a data source which shows a list of names, and a header for every time the 1st letter of the name changes (assume the list is alphabetized) - similar to how a contacts list would look like:
当然,此示例假定您已经以一种易于以这种方式实现适配器的方式构建了数据源 (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();
}
This example comes to solve a fairly specific issue, but I hope this gives you a good overview on how to handle different row types in a recycler, and allows you make the necessary adaptations in your own code to fit your needs.
这个例子解决了一个相当具体的问题,但我希望这能让你很好地了解如何在回收器中处理不同的行类型,并允许你在自己的代码中进行必要的调整以满足你的需求。
回答by ticofab
The trick is to create subclasses of ViewHolder and then cast them.
诀窍是创建 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;
And then, at runtime do something like this:
然后,在运行时做这样的事情:
@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;
}
}
Hope it helps.
希望能帮助到你。
回答by iGio90
According to Gil great answer I solved by Overriding the getItemViewType as explained by Gil. His answer is great and have to be marked as correct. In any case, I add the code to reach the score:
根据 Gil 很好的答案,我通过覆盖 Gil 解释的 getItemViewType 解决了这个问题。他的回答很棒,必须标记为正确。无论如何,我添加代码以达到分数:
In your recycler adapter:
在您的回收器适配器中:
@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));
}
By doing this, you can set whatever custom layout for whatever row!
通过这样做,您可以为任何行设置任何自定义布局!
回答by yubaraj poudel
It is quite tricky but that much hard, just copy the below code and you are done
这很棘手,但很难,只需复制以下代码即可完成
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);
}
}
}
enjoy !!!!
请享用 !!!!
回答by duggu
We can achieve multiple view on single RecyclerView from below way :-
我们可以通过以下方式在单个 RecyclerView 上实现多个视图:-
Dependencies on Gradle so add below code:-
对 Gradle 的依赖所以添加以下代码:-
compile 'com.android.support:cardview-v7:23.0.1'
compile 'com.android.support:recyclerview-v7:23.0.1'
RecyclerView in XML
XML 格式的 RecyclerView
<android.support.v7.widget.RecyclerView
????android:id="@+id/recyclerView"
????android:layout_width="match_parent"
????android:layout_height="match_parent"/>
Activity Code
活动代码
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);
First XML
第一个 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>
Second XML
第二个 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>
Third XML
第三个 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>
Now time to make adapter and this is main for showing different -2 view on same recycler view so please check this code focus fully :-
现在是制作适配器的时候了,这主要用于在同一个回收器视图上显示不同的 -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];
????}
}
You can check also this linkfor more information.
您也可以查看此链接以获取更多信息。
回答by Amandeep Rohila
You have to implement getItemViewType()
method in RecyclerView.Adapter
. By default onCreateViewHolder(ViewGroup parent, int viewType)
implementation viewType
of this method returns 0
. Firstly you need view type of the item at position for the purposes of view recycling and for that you have to override getItemViewType()
method in which you can pass viewType
which will return your position of item. Code sample is given below
您必须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);
// ...
}
回答by Rohit Singh
getItemViewType(int position) is the key
getItemViewType(int position) 是关键
In my opinion,the starting point to create this kind of recyclerView is the knowledge of this method. Since this method is optional to override therefore it is not visible in RecylerView class by default which in turn makes many developers(including me) wonder where to begin. Once you know that this method exists, creating such RecyclerView would be a cakewalk.
在我看来,创建这种recyclerView的出发点是对这个方法的了解。由于此方法是可选的,因此默认情况下它在 RecylerView 类中不可见,这反过来又使许多开发人员(包括我)想知道从哪里开始。一旦你知道这个方法存在,创建这样的 RecyclerView 将是一件轻而易举的事。
How to do it ?
怎么做 ?
You can create a RecyclerView
with any number of different Views(ViewHolders). But for better readability lets take an example of RecyclerView
with two Viewholders
.
Remember these 3 simplesteps and you will be good to go.
您可以RecyclerView
使用任意数量的不同视图(ViewHolders)创建一个。但是为了更好的可读性,让我们RecyclerView
以两个Viewholders
.
记住这3 个简单的步骤,你就可以开始了。
- Override public int
getItemViewType(int position)
- Return different ViewHolders based on the
ViewType
in onCreateViewHolder() method Populate View based on the itemViewType in
onBindViewHolder()
methodHere is a code snippet for you
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 } } }
- 覆盖公共整数
getItemViewType(int position)
- 根据
ViewType
onCreateViewHolder() 方法返回不同的 ViewHolders 根据
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 Code:
GitHub代码:
Here is a projectwhere I have implemented a RecyclerView with multiple ViewHolders.
这是我实现了一个带有多个 ViewHolders 的 RecyclerView的项目。
回答by ???
You can just return ItemViewType and use it. See below code:
您可以只返回 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);
}
回答by Vitaly
You can use the library: https://github.com/vivchar/RendererRecyclerViewAdapter
您可以使用该库: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 */
For each item, you should to implement a ViewRenderer, ViewHolder, SomeModel:
对于每个项目,您应该实现一个 ViewRenderer、ViewHolder、SomeModel:
ViewHolder - it is a simple view holder of recycler view.
ViewHolder - 它是一个简单的回收器视图的视图持有者。
SomeModel - it is your model with ItemModel
interface
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));
}
}
For more details you can look documentations.
有关更多详细信息,您可以查看文档。
回答by kmfish
You can use this library:
https://github.com/kmfish/MultiTypeListViewAdapter(written by me)
你可以使用这个库:
https: //github.com/kmfish/MultiTypeListViewAdapter(我写的)
- Better reuse the code of one cell
- Better expansion
- Better decoupling
- 更好地重用一个单元格的代码
- 更好的扩展
- 更好的解耦
Setup adapter:
设置适配器:
adapter = new BaseRecyclerAdapter();
adapter.registerDataAndItem(TextModel.class, LineListItem1.class);
adapter.registerDataAndItem(ImageModel.class, LineListItem2.class);
adapter.registerDataAndItem(AbsModel.class, AbsLineItem.class);
For each line item:
对于每个订单项:
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);
}
}