RecyclerView实现复杂布局
来源:互联网 发布:上海行知教育教学网点 编辑:程序博客网 时间:2024/05/18 17:23
在上一篇中我们简单的说了一下RecyclerView的基本使用方法,这一篇我们来说说如何去利用RecyclerView来实现复杂布局。为什么要实现复杂布局呢?因为我们在实际的项目开发中肯定不可能像之前写的Demo那样,Item里面就一个TextView,产品经理肯定会给我们提出各种各样的神奇需求(工作过的哥们都知道),所以实现复杂布局很有必要。先来看几个基本的知识点,如下:
1.先来看一下RecyclerView的使用场景:多种多样的列表、宫格和列表同时存在、分类列表比如通讯录
2.多种布局的保存:Type<---getItemViewType(int position)、RecyclerView.Holder(类比ListView的内部类Holder)、RecyclerView.Recycler(保存了一些缓存的机制,类比之前ListView中的convertView)
3.getItemViewType的作用:ItemType会保存在Holder内部类中、Holder根据position被缓存在cache中(当我们需要复用的时候,系统会在cache中拿holder,进而实现使用流畅)、
遍历缓存中的Holder,如果Type一致就返回当前的Holder
4.RecyclerView.Holder的简介:在RV中保存View的单位(它是包装了一个View,因为View是在Holder中的,ListView里面保存的是View,RV中保存的是Holder,这就是它们的区别)、记录在RV中的基本信息、需要一个是否被缓存的Flag标志
5.RecyclerView.Recycler的简介:RV中会缓存一些Holder,这些Holder会保存在一个map里面,这个map就是放在Recycler这个内部类中,多个RV会公用一个RecycleredPool,这个缓存池是一个静态内部类,Recycler中会配置一些缓存Size,里面有一个默认的缓存Size和一个公用的Pool的Size
6.和ListView的区别:Type已经是Holder的成员了、RV的缓存单位是Holder而不再是View了、RecycleredPool的缓存key是Type(如果Holder被缓存了,则是直接根据Type去寻找)
下面我们通过代码来看一下如何具体的实现多种Item的列表展示,首先来看列表Item的布局文件:
item_type_one.xml文件中的代码如下,里面放有一个ImageView和一个TextView:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="60dp" android:background="@android:color/white" android:orientation="horizontal" android:gravity="center_vertical"> <ImageView android:id="@+id/avatar" android:layout_width="40dp" android:layout_height="40dp" android:layout_marginLeft="20dp"/> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" tools:text="Archie" android:layout_marginLeft="20dp"/></LinearLayout>item_type_two.xml文件中的代码如下,里面放有一个ImageView和两个TextView:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="60dp" android:background="@android:color/white" android:orientation="horizontal" android:gravity="center_vertical"> <ImageView android:id="@+id/avatar" android:layout_width="40dp" android:layout_height="40dp" android:layout_marginLeft="20dp"/> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" tools:text="Archie" android:layout_marginLeft="20dp"/> <TextView android:id="@+id/content" android:layout_width="wrap_content" android:layout_height="wrap_content" tools:text="内容" android:layout_marginLeft="20dp" android:layout_marginTop="5dp"/> </LinearLayout></LinearLayout>item_type_three.xml文件中的代码如下,里面有两个ImageView和两个TextView:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="60dp" android:background="@android:color/white"> <ImageView android:id="@+id/avatar" android:layout_width="40dp" android:layout_height="40dp" android:layout_centerVertical="true" android:layout_marginLeft="20dp" /> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerVertical="true" android:layout_toRightOf="@+id/avatar" android:orientation="vertical"> <TextView android:id="@+id/name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" tools:text="Archie" /> <TextView android:id="@+id/content" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="20dp" android:layout_marginTop="5dp" tools:text="内容" /> </LinearLayout> <ImageView android:id="@+id/contentImage" android:layout_width="80dp" android:layout_height="45dp" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:layout_marginRight="20dp" /></RelativeLayout>接着我们去创建我们的数据实体,大多数情况下数据返回的都是有多种Type的,意思就是服务器返回给我们的数据是多种列表的(比如说数据源有list1,list2,list3,并且每一个集合中的字段还都不一样),这里我在代码中也给出了基于一个ViewModel去做类型的分发的实现方式,这里我就不讲这种实现方式了(最基本的实现方式),我在这里来讲讲基于多个Model的实现方式,这种方式的Model里面我们不做Type的处理,只给出数据字段,具体代码如下:
DataModelOne.java的代码,对应着第一种布局:
public class DataModelOne { public int avatarColor; public String name;}DataModelTwo.java的代码,对应着第二种布局:
public class DataModelTwo { public int avatarColor; public String name; public String content;}DataModelThree.java的代码,对应着第三种布局:
public class DataModelThree { public int avatarColor; public String name; public String content; public int contentColor;}好了,接下来我们要进行的是我们的重中之重,就是Adapter中的处理,首先我们在我们的Adapter中创建了一个addListByType的方法,在方法里面我们传递两个参数,一个是type,一个是list,作用就是把List根据Type去分配它的position,在实现这个方法前我们还需要创建两个数据集合,代码如下:
private List<Integer> types = new ArrayList<>();private Map<Integer,Integer> mPos = new HashMap<>();第一个types就相当于每个位置的type,这样的话get到每一个position都能拿到一个type,getItemViewType里面每一个position上的位置都能记录的很清楚,具体代码为:
@Overridepublic int getItemViewType(int position) { return types.get(position);}
@Overridepublic int getItemCount() { return types.size();}第二个mPos用来记录当前每一个List在types的起始位置,这样就可以来实现我们的addListByType方法了,具体实现为:
private void addListByType(int type,List list){ mPos.put(type,types.size()); for (int i =0;i<list.size();i++){ types.add(type); }}然后我们在Adapter中开始创建我们的类型,这里定义为静态常量(实际项目中也是这样),具体代码为:
public static final int TYPE_ONE = 1;public static final int TYPE_TWO = 2;public static final int TYPE_THREE = 3;然后我们来定义一个方法去调用addListByType进行数据的添加,这里创建方法addList,参数为不同类型的数据集合,代码为:
public void addList(List<DataModelOne> list1, List<DataModelTwo> list2, List<DataModelThree> list3){ addListByType(TYPE_ONE,list1); addListByType(TYPE_TWO,list2); addListByType(TYPE_THREE,list3); this.list1 = list1; this.list2 = list2; this.list3 = list3;}
好了做完这些以后,下面我们来看一下我们的ViewHolder该如何实现呢?这里我们定义一个抽象的父类,类中定义两个方法,一个是构造方法,一个是抽象的bindHolder方法,这里用到了泛型(泛型擦除),这样便于子类在继承之后可以指定它自己的泛型类型,这里分别为三种类型的Item创建三个ViewHolder类,分别为TypeOneViewHolder、TypeTwoViewHolder、TypeThreeViewHolder,这里实现的原理都是一样的,我给出其中一个的代码,其它的大家自己可以下载源码后自行查看:
public class TypeOneViewHolder extends TypeAbstractViewHolder<DataModelOne>{ public ImageView avatar; public TextView name; public TypeOneViewHolder(View itemView) { super(itemView); avatar = (ImageView) itemView.findViewById(R.id.avatar); name = (TextView) itemView.findViewById(R.id.name); itemView.setBackgroundColor(Color.YELLOW); } @Override public void bindHolder(DataModelOne model) { avatar.setBackgroundResource(model.avatarColor); name.setText(model.name); }}
好,ViewHolder准备好了之后,下面我们来看适配器中的onCreateViewHolder和onBindViewHolder这两个方法的实现,onCreateViewHolder中很简单,就是加载我们的View,具体实现为:
@Overridepublic RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { switch (viewType) { case TYPE_ONE: return new TypeOneViewHolder(mInflater.inflate( R.layout.item_type_one, parent, false)); case TYPE_TWO: return new TypeTwoViewHolder(mInflater.inflate( R.layout.item_type_two, parent, false)); case TYPE_THREE: return new TypeThreeViewHolder(mInflater.inflate( R.layout.item_type_three, parent, false)); } return null;}
重点是来看我们的onBindViewHolder,这个方法是进行数据的绑定,这里我们先去获取viewType,拿到每一个position的Type,然后再去拿一个realPosition,这个值就是传进来的position减去我们拿到的起始位置的position,这样计算出来的realPosition就是对应每个列表中的position,最后通过不同的类型去绑定数据,具体实现为:
@Overridepublic void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { int viewType = getItemViewType(position); int realPosition = position - mPos.get(viewType); switch (viewType) { case TYPE_ONE: ((TypeOneViewHolder) holder) .bindHolder(list1.get(realPosition)); break; case TYPE_TWO: ((TypeTwoViewHolder) holder) .bindHolder(list2.get(realPosition)); break; case TYPE_THREE: ((TypeThreeViewHolder) holder) .bindHolder(list3.get(realPosition)); break; }}这样我们就完成了利用RecyclerView去实现多种Item布局的操作,这里给出项目案例的源码地址,本篇的实现参见工程中的ComplexRVDemo这个model,地址为:https://github.com/JArchie/RecyclerViewDemo,谢谢大家,欢迎各位的指正!
- RecyclerView实现复杂布局
- 学习RecyclerView优雅实现复杂列表布局
- RecyclerView实现复杂首页(条目)布局
- recyclerView实现复杂布局的好处
- 优雅地实现RecyclerView的复杂布局
- 强大的RecyclerView实现复杂布局
- RecyclerView GridLayoutManager实现复杂的列数变化的布局
- 不一样的RecyclerView优雅实现复杂列表布局(一)
- 不一样的RecyclerView优雅实现复杂列表布局(二)
- Recyclerview根据setSpanSizeLookup实现复杂布局(不用嵌套)
- MultiType-Adapter 优雅的实现RecyclerVIew中的复杂布局
- RecyclerView GridLayoutManager实现复杂的列数变化的布局
- android RecyclerView的复杂布局
- android RecyclerView的复杂布局
- 复杂RecyclerView实现
- 复杂RecyclerView的实现
- 复杂RecyclerView的实现
- RecyclerView实现复杂页面
- OJ-------从单向链表中删除指定节点
- 机器学习课程 笔记
- Ubuntu12.10编译MPTCP
- Python 日志组件学习(一)
- React Native 配置环境(iOS and Android)
- RecyclerView实现复杂布局
- 美国大学最新排名较以往变化不大 名校对语言成绩(雅思)要求更高
- scala编程实战 scala编程实战pdf 下载
- Hibernate
- shrio权限管理filterChainDefinitions过滤器配置
- 安卓使用Camera实现拍照并保存到内存卡中
- 字符串
- Xcode真机运行报错linker command failed with exit code 1 (use -v to see invocation)
- mysql replace into 用法笔记