再循环查看和处理不同types的行通货膨胀
我试图与新的RecyclerView
,但我找不到一个RecyclerView
与不同types的行/ cardviews得到膨胀的一个例子。
使用ListView
我会重写getViewTypeCount
和getItemViewType
,以处理不同types的行。
我应该像“老”的方式做,或者我应该用LayoutManager
做些什么? 我想知道是否有人能指点我正确的方向。 因为我只能find一种types的例子。
我想要列出一些略有不同的卡片。 或者我应该只使用一个scrollView
与cardViews
里面…让它没有适配器和recyclerView
?
处理类似于iOS的UITableView的行/段逻辑在Android中并不像在iOS中那么简单,但是当您使用RecyclerView时 – 您可以做的更大的灵活性。
最后,所有关于如何确定在适配器中显示的视图types。 一旦你明白了,这应该是轻松的航行(不是真的,但至less你会有这种sorting)。
适配器公开了两个你应该覆盖的方法:
getItemViewType(int position)
此方法的默认实现将始终返回0,表示只有1种types的视图。 在你的情况,它不是这样,所以你需要find一种方式来断言哪一行对应于哪种视图types。 不像iOS那样用行和段来pipe理这个,在这里你只能依靠一个索引,而且你需要使用开发人员的技能来知道一个位置与一个段头相关的时间,一个正常的行。
createViewHolder(ViewGroup parent, int viewType)
无论如何,您需要重写此方法,但通常人们只是忽略viewType参数。 根据视图types,您需要充实正确的布局资源并相应地创build视图持有者。 RecyclerView将以避免不同视图types的冲突的方式处理回收不同视图types。
如果您打算使用默认的LayoutManager,比如LinearLayoutManager
,那么您应该很好。 如果您打算制作自己的LayoutManager实施,则需要更加努力。 唯一需要使用的API是findViewByPosition(int position)
,它在给定的findViewByPosition(int position)
给出一个给定的视图。 由于您可能想要根据视图的types来进行不同的布局,因此您可以select以下选项:
-
通常在使用ViewHolder模式时,您可以使用视图持有者来设置视图的标签。 您可以在运行时在布局pipe理器中使用它,通过在视图持有者中添加一个字段来表示该视图的types。
-
既然你需要一个函数来确定哪个位置与哪个视图types相关,那么你可能会使得这个方法在全局上以某种方式访问(也许是一个单独的类来pipe理数据?),然后你可以简单地根据的位置。
这是一个代码示例:
// 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()); } }
当然,这个例子假定你已经构build了你的数据源(myData),这样就很容易以这种方式实现一个适配器。 作为一个例子,我将向您展示如何构build一个显示名称列表的数据源,以及每当名称的第一个字母改变时(假设列表按字母顺序排列)的标题 – 类似于联系人列表将如下所示:
// 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(); }
这个例子解决了一个相当具体的问题,但是我希望这给你一个很好的概述如何在回收站处理不同的行types,并允许你在自己的代码中进行必要的修改以适应你的需求。
诀窍是创buildViewHolder的子类,然后施放它们。
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; } }
希望它有帮助。
根据吉尔伟大的答案,我解决了重写getItemViewType由吉尔解释。 他的回答很好,必须标明正确。 无论如何,我添加代码来达到分数:
在您的回收站适配器中:
@Override public int getItemViewType(int position) { int viewType = 0; // add here your booleans or switch() to set viewType at your needed // IE 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)); }
通过这样做,您可以为任何行设置任何自定义布局!
这是相当棘手的,但很难,只是复制下面的代码,你就完成了
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); } } }
请享用 !!!!
我们可以从下面的方式实现对单个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_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]; } }
您也可以查看此链接了解更多信息。
你必须在RecyclerView.Adapter
实现getItemViewType()
方法。 默认情况下, onCreateViewHolder(ViewGroup parent, int viewType)
实现此方法的viewType
返回0
。 首先你需要查看视图types的位置为了视图回收的目的,为此,你必须重写getItemViewType()
方法,你可以在其中传递viewType
来返回你的item的位置。 代码示例如下
@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); // ... }
你可以返回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); }
你可以使用库: 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)); } }
欲了解更多详情,你可以看看文件。
你可以使用这个库:
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); } }