我的Android进阶之旅强烈推荐 一种优雅的方式实现RecyclerView条目多类型
Posted 欧阳鹏
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我的Android进阶之旅强烈推荐 一种优雅的方式实现RecyclerView条目多类型相关的知识,希望对你有一定的参考价值。
前言
两年之前,看到一篇文章 【一种优雅的方式实现RecyclerView条目多类型】 ,当时感觉很不错,也将这篇文章的思想运用到了自己的实际项目中。
在后续的工作中,我也给同事们推荐了此篇文章,这里转载一下这个内容在此处备份。
PS : 以下内容转载于: 【一种优雅的方式实现RecyclerView条目多类型】
转载请标明出处:
http://blog.csdn.net/xuehuayous/article/details/80021325;
本文出自:【Kevin.zhou的博客】
下面以一个故事来讲来说明这中方式是怎么实现的。
放弃vlayout
大家都了解一般首页是非常复杂的,去年初项目引入vlayout来解决首页复杂布局的问题,后来对vlayout和databinding结合进行了封装,使用起来更方便简单,不仅首页使用,很多页面都在用,还封装了单纯列表样式的Activity,刷新加载的Activity,这样很开心的过了很久。由于vlayout项目一直比较活跃,在满足各种各样的需求上一直在打补丁,我也是一直在把它更新为最新版本,直到又一次更新我的的列表不显示内容了,经过一上午的排查,找到了问题。是在合并一个同学的PR时引入的,当时我还提了个issue 升级后出现onBindViewHolder未分发的问题,并给作者提了建议,加强Code Review,其实这时候我就没有那么happy了。
在一次需求中,PM提出了可以删除列表中某一条目的需求,在之前封装的基础上很简单就实现了。这时想加一个移除的动画吧,让APP活泼点,不是那么生硬。这可难住了我,一上午硬是没搞出来,在别的同学的issue 怎么正确的使用notifyItemRemoved,正是这个问题,使得我有了放弃使用vlayout的想法。不禁问自己,我为什么要使用它,没错就是为了使复杂布局更方便管理,现在看来有悖于初衷。也许vlayout有删除动画的简单实现方式,而我没有找到,但是我决定不再使用它。
寻找轮子
放弃之后面临的另一个问题是需求还是要做,项目还是要按时上线,冒出了第一个想法是找找其他的轮子吧,MultiItem github上的介绍是一个优雅的实现多类型的RecyclerView类库,窃喜,这不正是我想要的。他的思想是给BaseItemAdapter(设置给RecyclerView)注册一系列的Adapter,然后根据需要处理的类来区分是要选择哪个被代理的Adapter。
// 初始化adapter
BaseItemAdapter adapter = new BaseItemAdapter();
// 为TextBean数据源注册ViewHolderManager管理类
adapter.register(TextBean.class, new TextViewManager());
// 为更多数据源注册ViewHolderManager管理类
adapter.register(ImageTextBean.class, new ImageAndTextManager());
adapter.register(ImageBean.class, new ImageViewManager());
// 为RecyclerView设置Adapter
recyclerView.setAdapter(adapter);
我要做的就是快速拿它匹配下我的场景,能不能满足我的需求。
- 是否支持多种类型条目?废话肯定支持;
- 是否支持不同条目不同数据类型?人家就是很久需要处理的数据类型来进行选择的,肯定没问题;
- 能不能支持一个数据类型对应多个样式?我看作者也是支持的,即通过数据实体中的标志来判断使用哪个Adapter;
- 能不能支持一个数据实体对应多个样式?由于是基于数据的类型进行选择代理Adapter的,这看来是无法实现。
我的微笑还没收场,就尴尬的定住了,5秒钟后,晃过神来,为什么我不按照这种思想自己封装一个。说实话我对作者的代理Adapter的管理还是不太满意的,这种思想很好,还是忍不住给作者点赞,那就自己来撸个轮子吧。
需求迭代
简单列表
PM在一次迭代过程中提出了要加一个新闻列表的需求,很简单,就是左边一个图片,右边一个标题、来源、发布时间,点击可以查看详情。
你一看,心中默念so easy,三下五除二,你就用RecyclerView很快实现了。
activity xml layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.kevin.myapplication.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
实体对象
public class News {
public String imgUrl = "";
public String content = "";
public String source = "";
public String time = "";
public String link = "";
}
adapter
public class NewsAdapter extends RecyclerView.Adapter<NewsAdapter.ViewHolder> {
private List<News> dataItems = new ArrayList<>();
public void setDataItems(List<News> dataItems) {
this.dataItems = dataItems;
notifyDataSetChanged();
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_news, parent, false);
ViewHolder holder = new ViewHolder(view);
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
News news = dataItems.get(position);
holder.tvContent.setText(news.content);
holder.tvSource.setText(news.source);
holder.tvTime.setText(news.time);
Glide.with(holder.itemView.getContext()).load(news.imgUrl).into(holder.ivPic);
}
@Override
public int getItemCount() {
return dataItems.size();
}
static class ViewHolder extends RecyclerView.ViewHolder {
ImageView ivPic;
TextView tvContent;
TextView tvSource;
TextView tvTime;
public ViewHolder(View view) {
super(view);
ivPic = view.findViewById(R.id.iv_pic);
tvContent = view.findViewById(R.id.tv_content);
tvSource = view.findViewById(R.id.tv_source);
tvTime = view.findViewById(R.id.tv_time);
}
}
}
adapter item layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp">
<ImageView
android:id="@+id/iv_pic"
android:layout_width="0dp"
android:layout_height="80dp"
android:scaleType="centerCrop"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/tv_content"
app:layout_constraintTop_toTopOf="parent"
tools:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/tv_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:ellipsize="end"
android:maxLines="2"
android:textColor="#333333"
android:textSize="18sp"
app:layout_constraintHorizontal_chainStyle="spread"
app:layout_constraintHorizontal_weight="2"
app:layout_constraintLeft_toRightOf="@+id/iv_pic"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="这是一条新闻,这是一条新闻,这是一条新闻" />
<TextView
android:id="@+id/tv_source"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:textColor="#888888"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="@+id/iv_pic"
app:layout_constraintLeft_toRightOf="@+id/iv_pic"
tools:text="澎湃新闻" />
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:textColor="#888888"
android:textSize="12sp"
app:layout_constraintBottom_toBottomOf="@+id/iv_pic"
app:layout_constraintLeft_toRightOf="@+id/tv_source"
tools:text="07:33" />
<View
android:layout_width="0dp"
android:layout_height="1px"
android:layout_margin="10dp"
android:background="#EEEEEE"
app:layout_constraintTop_toBottomOf="@id/iv_pic" />
</android.support.constraint.ConstraintLayout>
看一下实现,还不错的样子。
扩充样式
某天产品经理找到你说,只有一张图片的看着太单调了,能不能扩充出另外一种样式,一张图片的时候还是原来的样子,如果三张图片的时候上面是标题,下面是图片。你觉得没什么,也比较好实现,就没有做任何反抗去做了。
应该是这样,在之前一个图片的ViewHolder基础上扩展一个三个图片的ViewHoder,通过实体对象的图片数量进行区分是选择哪一个ViewHolder,不同的ViewHolder绑定不同的数据。
修改实体对象
把原来的String类型的图片数据改为List的集合。
public class News {
public List<String> imgUrls = null;
public String content = "";
public String source = "";
public String time = "";
public String link = "";
}
新样式的xml layout
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:paddingTop="10dp">
<TextView
android:id="@+id/tv_content"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:ellipsize="end"
android:maxLines="2"
android:textColor="#333333"
android:textSize="18sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="这是一条新闻,这是一条新闻,这是一条新闻" />
<ImageView
android:id="@+id/iv_pic1"
android:layout_width="0dp"
android:layout_height="80dp"
android:layout_marginTop="10dp"
android:scaleType="centerCrop"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/iv_pic2"
app:layout_constraintTop_toBottomOf="@+id/tv_content"
tools:src="@mipmap/ic_launcher" />
<ImageView
android:id="@+id/iv_pic2"
android:layout_width="0dp"
android:layout_height="80dp"
android:layout_marginLeft="4dp"
android:layout_marginTop="10dp"
android:scaleType="centerCrop"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@+id/iv_pic1"
app:layout_constraintRight_toLeftOf="@+id/iv_pic3"
app:layout_constraintTop_toBottomOf="@+id/tv_content"
tools:src="@mipmap/ic_launcher" />
<ImageView
android:id="@+id/iv_pic3"
android:layout_width="0dp"
android:layout_height="80dp"
android:layout_marginLeft="4dp"
android:layout_marginTop="10dp"
android:scaleType="centerCrop"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@+id/iv_pic2"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_content"
tools:src="@mipmap/ic_launcher" />
<TextView
android:id="@+id/tv_source"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:textColor="#888888"
android:textSize="12sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toBottomOf="@+id/iv_pic1"
tools:text="澎湃新闻" />
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:textColor="#888888"
android:textSize="12sp"
app:layout_constraintLeft_toRightOf="@+id/tv_source"
app:layout_constraintTop_toTopOf="@+id/tv_source"
tools:text="07:33" />
<View
android:layout_width="0dp"
android:layout_height="1px"
android:layout_margin="10dp"
android:background="#EEEEEE"
app:layout_constraintTop_toBottomOf="@id/tv_source" />
</android.support.constraint.ConstraintLayout>
Adapter改造
复写getItemViewType方法,通过判断图片的个数是不是3个来区分样式。如果是则ViewType为1,如果不是则ViewType为0。
@Override
public int getItemViewType(int po以上是关于我的Android进阶之旅强烈推荐 一种优雅的方式实现RecyclerView条目多类型的主要内容,如果未能解决你的问题,请参考以下文章
我的OpenGL学习进阶之旅解决Android OpenGL ES 调试工具 GAPID 无法识别Android设备的问题
我的OpenGL学习进阶之旅解决Android OpenGL ES 调试工具 GAPID 无法识别Android设备的问题
我的Android进阶之旅Android Studio中如何快速查找空行
我的Android进阶之旅------>MIME类型大全