RecyclerView中的ViewType
1. 前言
在接触了RecyclerView了之后,就慢慢的用它代替了ListView的使用,结合CardView能创建出比较好看的列表,但是这根本就不够诶,单纯的列表好像没什么意思了,好多应用的信息量比较大而且很复杂,每个item需要用到不同的布局文件来显示不同的信息= =,之前写来写去都是简单的列表,根本就没接触到ViewType这个东西,稍微熟悉并使用了之后,才发现= =RecyclerView还可以这样用噢(原谅我的无知)。
看下面的这张图= =,豌豆荚里面的列表项,基本上每个item都不一样,下面用一个自己弄的小demo来演示如何在一个RecyclerView中实现多个item。
2. ViewType使用方法
RecyclerView中的ViewType就是一个int类型的数字,用来将每个item归类,同一类的item使用着同一套布局文件,我们都知道使用RecyclerView的时候会用到Adapter,还会用到ViewHolder。一个ViewHolder对应着一类布局文件,也就是对应着一类item,还需要用Adapter来针对不同的ViewHolder来绑定不同的数据。
2.1 定义不同种类的item视图
先定义了三种item的xml视图,在这里就不给出了,非常简单的布局,随便自己定义下就好了。对应的需要定义三种不同的ViewHolder:
class ViewHolderOne extends RecyclerView.ViewHolder {
@Bind(R.id.item_recyclerview_demo_user_avatar)
public ImageView mUserAvatar;
@Bind(R.id.item_recyclerview_demo_user_name)
public TextView mUserName;
@Bind(R.id.item_recyclerview_demo_user_info)
public TextView mUserInfo;
@Bind(R.id.item_recyclerview_demo_selected)
public ImageView mSelected;
public ViewHolderOne(View view) {
super(view);
ButterKnife.bind(this, view);
}
}
class ViewHolderTwo extends RecyclerView.ViewHolder {
@Bind(R.id.item_recyclerview_demo_user_avatar)
public ImageView mUserAvatar;
@Bind(R.id.item_recyclerview_demo_user_name)
public TextView mUserName;
@Bind(R.id.item_recyclerview_demo_user_info)
public TextView mUserInfo;
@Bind(R.id.item_recyclerview_demo_selected)
public ImageView mSelected;
public ViewHolderTwo(View view) {
super(view);
ButterKnife.bind(this, view);
}
}
class ViewHolderThree extends RecyclerView.ViewHolder {
@Bind(R.id.item_recyclerview_demo_user_avatar)
public ImageView mUserAvatar;
@Bind(R.id.item_recyclerview_demo_user_name)
public TextView mUserName;
@Bind(R.id.item_recyclerview_demo_user_info)
public TextView mUserInfo;
@Bind(R.id.item_recyclerview_demo_selected)
public ImageView mSelected;
public ViewHolderThree(View view) {
super(view);
ButterKnife.bind(this, view);
}
}
为了图个方便,三种布局里面主要的控件都是一样的,只是有些地方不同,具有id的一些控件都是相同的,所以ViewHolder中的东西都是一样的,也可以根据自己不同的需求来定义完全不同的ViewHolder(千万不要受我的影响 = =)。
2.2 自定义Adapter
定义好了三种ViewHolder之后,就需要根据不同的需求,在Adapter里面识别并运用这些ViewHolder,Adapter里面已经定义好了一些方法,只需要重写getItemViewType(int position)
方法,给每个固定的position上的item返回一个固定的类型(ViewType)就能方便的表明每个item需要的ViewHolder。
class MyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
//User是一个自定义类,代表封装的数据类型
private List<User> mUsers;
//三种不同的ViewType类型,事先用常量定义好
public static final int VIEW_TYPE_ONE = 1;
public static final int VIEW_TYPE_TWO = 2;
public static final int VIEW_TYPE_THREE = 3;
public MyAdapter(List<User> users) {
mUsers = users;
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
RecyclerView.ViewHolder myViewHolder = null;
//根据不同的ViewType类型,来返回不同的ViewHolder
switch (viewType) {
case VIEW_TYPE_ONE:
myViewHolder = new ViewHolderOne
(LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_item_one, parent, false));
break;
case VIEW_TYPE_TWO:
myViewHolder = new ViewHolderTwo
(LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_item_two, parent, false));
break;
case VIEW_TYPE_THREE:
myViewHolder = new ViewHolderThree
(LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_item_three, parent, false));
break;
}
return myViewHolder;
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
//根据不同的ViewType类型,进行不同的数据绑定操作
switch (holder.getItemViewType()) {
case VIEW_TYPE_ONE:
ViewHolderOne holderOne = (ViewHolderOne) holder;
holderOne.mUserAvatar.setImageResource(R.mipmap.ic_launcher);
holderOne.mUserName.setText(mUsers.get(position).getUserName());
holderOne.mUserInfo.setText(mUsers.get(position).getInfo());
break;
case VIEW_TYPE_TWO:
ViewHolderTwo holderTwo = (ViewHolderTwo) holder;
holderTwo.mUserAvatar.setImageResource(R.mipmap.user_avatar);
holderTwo.mUserName.setText(mUsers.get(position).getUserName());
holderTwo.mUserInfo.setText(mUsers.get(position).getInfo());
break;
case VIEW_TYPE_THREE:
ViewHolderThree holderThree = (ViewHolderThree) holder;
holderThree.mUserAvatar.setImageResource(R.mipmap.ic_launcher);
holderThree.mUserName.setText(mUsers.get(position).getUserName());
holderThree.mUserInfo.setText(mUsers.get(position).getInfo());
break;
}
}
@Override
public int getItemCount() {
if (null != mUsers) return mUsers.size();
else return 0;
}
//重写方法,给每个position上的item返回一个固定的ViewType类型
//如果返回的ViewType类型不固定,则会出现各种item布局变化的情况,可能还会触发bug
@Override
public int getItemViewType(int position) {
return mUsers.get(position).getType();
}
}
在Adapter里面涉及到了一个User.java的数据类型,下面是其代码:
public class User implements Parcelable {
private int type;
private String info;
private String userName;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public User() {
}
public User(int t, String u, String i) {
type = t;
userName = u;
info = i;
}
}
2.3 使用定义好了的Adapter
一切都准备好了,只需要将Adapter给RecyclerView装上就可以了。再装上一个用来下拉刷新添加数据的控件。
mAdapter = new MyAdapter(mUsers);
mRecyclerView.setLayoutManager(new LinearLayoutManager(getApplicationContext()));
mRecyclerView.setItemAnimator(new DefaultItemAnimator());
mRecyclerView.setAdapter(mAdapter);
使用的效果如下,再加以细节上的处理,一个拥有多个ViewType的RecyclerView就诞生了= =: