前言

在日常的开发中我们经常会在一个列表数据中展示多种样式。
比如一个新闻列表,顶部是一个焦点Banner,然后是展示文章列表,文章中间可能插入某个图片广告,底部是一个加载更多/没有更多数据的加载状态视图。

自定义ViewType实现

熟悉RecyclerView的都知道,我们可以通过设置列表每个位置对应的viewType来加载指定的View,这也是所有多类型列表框架的基本实现原理。

  1. 适用于数据和业务不复杂,且项目内使用场景较少的情况
  2. 优点:扩展性高,可随意定制。
  3. 缺点:耦合性较高,业务扩展较麻烦。

简单的多类型列表实现代码如下:

class CustomAdapter(private val datas: MutableList<Person>) : RecyclerView.Adapter<ViewHolder>() {override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {return when (viewType) {Person.ITEM_HEADER -> {ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_header, parent, false))}Person.ITEM_FOOT -> {ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_foot, parent, false))}Person.ITEM_STUDENT -> {ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_student, parent, false))}else -> {ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_teacher, parent, false))}}}override fun getItemCount(): Int = datas.size + 2 //+2。为了显示头部和底部override fun getItemViewType(position: Int): Int {return when (position) {0 -> {Person.ITEM_HEADER}datas.size + 1 -> {Person.ITEM_FOOT}else -> {datas[position - 1].itemType}}}override fun onBindViewHolder(holder: ViewHolder, position: Int) {when (holder.itemViewType) {Person.ITEM_STUDENT -> {holder.tvStudent.text = datas[position - 1].name}Person.ITEM_TEACHER -> {holder.tvTeacher.text = datas[position - 1].name}}}
}

BRVAH框架(BaseRecyclerViewAdapterHelper)

大名鼎鼎的BaseRecyclerViewAdapterHelper,GitHub上Star接近2w。
RecycleView所有的操作这个框架基本都能实现。今天我们只单独说一下,如何用BRVAH框架实现多类型列表。
根据BRVAH框架多类型官方文档,目前实现多类型列表,BRVAH框架根据不同的场景提供了三个方案。

allprojects {repositories {...maven { url 'https://jitpack.io' }}
}
dependencies {implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.2'
}

1.BaseMultiItemQuickAdapter

  1. 适用于类型较少,业务不复杂的场景,便于快速使用。
  2. 优点: 使用简单,代码量少。封装的较为严密,头部和底部视图可直接添加,无需额外添加itemViewType。
  3. 缺点:数据类必须实现MultiItemEntity接口,数据类不够灵活。
class MultiItemAdapter(mContext: Context, data: MutableList<Person>?) : BaseMultiItemQuickAdapter<Person, ViewHolder>(data) {init {addItemType(Person.ITEM_TEACHER, R.layout.item_teacher)addItemType(Person.ITEM_STUDENT, R.layout.item_student)mContext.run {addHeaderView(getLayoutView(R.layout.item_header)) //添加头部视图addFooterView(getLayoutView(R.layout.item_foot)) //添加底部视图}}override fun convert(holder: ViewHolder, item: Person) {when (holder.itemViewType) {Person.ITEM_STUDENT -> {holder.tvStudent.text = item.name}Person.ITEM_TEACHER -> {holder.tvTeacher.text = item.name}}}}
open class Person : MultiItemEntity {companion object {val ITEM_HEADER = 0val ITEM_TEACHER = 1val ITEM_STUDENT = 2val ITEM_FOOT = 3}var name: String = ""override val itemType: Intget() = if (name.contains("老师")) {ITEM_TEACHER} else {ITEM_STUDENT}}

2.BaseDelegateMultiAdapter

通过代理类的方式,返回布局 id 和 item 类型;适用于数据类不方便扩展的情况。

  1. 本质上与BaseMultiItemQuickAdapter相同,只是将获取itemType的方式改为了代理实现。
  2. 优点:降低了对数据类的要求,使用更灵活。
  3. 缺点:增加了Adapter的负担,使得该类不易扩展。
class DelegateMultiAdapter(mContext: Context, data: MutableList<Person>?) : BaseDelegateMultiAdapter<Person, ViewHolder>(data) {init {// 第一步,设置代理setMultiTypeDelegate(object : BaseMultiTypeDelegate<Person>() {override fun getItemType(data: List<Person>, position: Int): Int {return if (data[position].name.contains("老师")) {Person.ITEM_TEACHER} else {Person.ITEM_STUDENT}}})// 第二部,绑定 item 类型getMultiTypeDelegate()?.run {addItemType(Person.ITEM_TEACHER, R.layout.item_teacher)addItemType(Person.ITEM_STUDENT, R.layout.item_student)}mContext.run {addHeaderView(getLayoutView(R.layout.item_header)) //添加头部视图addFooterView(getLayoutView(R.layout.item_foot)) //添加底部视图}}override fun convert(holder: ViewHolder, item: Person) {when (holder.itemViewType) {Person.ITEM_STUDENT -> {holder.tvStudent.text = item.name}Person.ITEM_TEACHER -> {holder.tvTeacher.text = item.name}}}
}

3.BaseBinderAdapter

当前多类型列表最广泛的使用—Binder模式。极大的业务解耦,几乎适用于任何多类型列表的情况。

  1. 当有多种条目的时候,避免在convert()中做太多的业务逻辑,把逻辑放在对应的 ItemProvider 中。以及最大化自定义VH类型。
  2. 优点:耦合性低,每种类型都在自己的Binder里面完成;数据类型完全没有限制。
  3. 缺点:每个类型都需要一个Binder&一个独自的数据类型,代码量增多。
class BinderAdapter constructor(mContext: Context, list: MutableList<Any>? = null) : BaseBinderAdapter(list) {init {addItemBinder(Teacher::class.java, TeacherBinder())addItemBinder(Student::class.java, StudentBinder())/***通过Binder设置头部和底部* 对于与数据关联的头部和底部来说,这样设置更灵活* 但是也额外增加了一些代码*/addItemBinder(Header::class.java, HeaderBinder())addItemBinder(Foot::class.java, FootBinder())/*mContext.run {addHeaderView(getLayoutView(R.layout.item_header)) //添加头部视图addFooterView(getLayoutView(R.layout.item_foot)) //添加底部视图}*/}
}
class TeacherBinder : BaseItemBinder<Teacher, ViewHolder>() {override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {return ViewHolder(LayoutInflater.from(parent.context).inflate(R.layout.item_teacher, parent, false))}override fun convert(holder: ViewHolder, data: Teacher) {holder.tvTeacher.text = data.name}
}

MultiType框架(MultiType)

专为RecycleView打造的优秀的多类型列表框架。
使用上与BRVAH框架的BaseBinderAdapter基本无二。
相对BRVAH框架来说更精简,更专业。
如果你的应用只需要用到多类型列表,并不需要RecycleView复杂操作,那么使用这个就能完全满足你的需要。

dependencies {implementation 'com.drakeet.multitype:multitype:4.2.0'
}
val adapter = MultiTypeAdapter()with(adapter) {register(Teacher::class.java, TeacherItemBinder())register(Student::class.java, StudentItemBinder())register(Header::class.java, HeaderItemBinder())register(Foot::class.java, FootItemBinder())}val list = mutableListOf<Any>()list.add(Header())getDatas().forEach {when (it.itemType) {Person.ITEM_TEACHER -> {val s = Teacher()s.name = it.namelist.add(s)}Person.ITEM_STUDENT -> {val s = Student()s.name = it.namelist.add(s)}}}list.add(Foot())adapter.items = listrv.adapter = adapter

Adapter“加法”(MergeAdapter)

MergeAdapter 是 recyclerview 1.2.0-alpha02 中提供的新类,它使您可以顺序组合多个 adapter,以在单个 RecyclerView 中显示。 这使您可以更好地封装 adapter,而不必将许多数据源组合到单个 adapter 中,从而使它们集中并复用。

官方“合并”Adapter,将一个 Adapter 负责多套布局,拆分为每个 Adapter 只处理一个布局,大大降低代码耦合,这是单一职责原则。
对于现有业务的改造具有很大优势,无需对已有的Adapter进行修改,例如添加头部和底部视图。
对于简单多类型的列表业务拆解也非常适用,无需改造数据类,直接将多类型的代码抽离成多个Adapter。

  1. 优点: 业务改造上有一定优势,对已有代码改动较小。
  2. 缺点: 列表展示的顺序局限性较大;无法处理不确定性的,动态类型的复杂视图。
  implementation 'androidx.recyclerview:recyclerview:1.2.0-alpha02'
class MergeActivity : AppCompatActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.layout_rv)title = "MergeAdapter"val teacherAdapter = TeacherAdapter(getDatas().filter { it.name.contains("老师") })val studentAdapter = StudentAdapter(getDatas().filter { !it.name.contains("老师") })val mergeAdapter = MergeAdapter(HeaderAdapter(), teacherAdapter, studentAdapter, FootAdapter())rv.adapter = mergeAdapter}
}

效果截图

总结

  1. 如果应用中多类型列表较少,而且比较简单完全可以自定义实现。
  2. 如果应用中多类型列表较多,但是RecycleView没有其他复杂的操作可以使用MultiType框架。
  3. 如果应用中不仅有多类型列表,而且有各种RecycleView动画,拖动等复杂操作,使用BRVAH框架就是一个不错的选择。
  4. 如果仅仅是对应用的业务进行简单改造,又不想进行大幅度修改MergeAdapter便是最好的选择。

Demo代码

Github:https://github.com/MyAndroidDemo/MultiTyperRecyclerView

Android RecyclerView多样式列表实践指南相关推荐

  1. 美图Android编译速度优化实践指南

    分享嘉宾:张仙华 美图 资深开发工程师 分享嘉宾:张仙华,美图秀秀android团队资深研发工程师,负责编译加速.性能优化.架构设计等公共基础相关工作 导读:本文的主题是美图秀秀的Android编译速 ...

  2. android两张图片切换,android recyclerview 切换列表视图

    一种是编写两个Adapter,切换Adapter的方式来实现切换列表视图.另一种方式是同一个Adapter切换布局layout的方式来切换视图 直接复制现在视图,控件ID未作变更,这样可以更改最少的代 ...

  3. 《OpenGL ES应用开发实践指南:Android卷》—— 2.3 定义空气曲棍球桌子的结构...

    本节书摘来自华章出版社<OpenGL ES应用开发实践指南:Android卷>一 书中的第2章,第2.3节,作者:(美)Kevin Brothaler ,更多章节内容可以访问云栖社区&qu ...

  4. 《OpenGL ES应用开发实践指南:Android卷》—— 2.2 不要从头开始

    本节书摘来自华章出版社<OpenGL ES应用开发实践指南:Android卷>一 书中的第2章,第2.2节,作者:(美)Kevin Brothaler ,更多章节内容可以访问云栖社区&qu ...

  5. android开发 RecyclerView 瀑布列表布局

    android开发 RecyclerView 瀑布列表布局 1.写一个内容的自定义小布局: <?xml version="1.0" encoding="utf-8& ...

  6. Android RecyclerView、ListView实现单选列表的优雅之路.

    一 概述: 这篇文章需求来源还是比较简单的,但做的优雅仍有值得挖掘的地方. 需求来源:一个类似饿了么这种电商优惠券的选择界面:  其实就是 一个普通的列表,实现了单选功能,  效果如图:    (不要 ...

  7. 《OpenGL ES应用开发实践指南:Android卷》—— 3.7 练习

    本节书摘来自华章出版社<OpenGL ES应用开发实践指南:Android卷>一 书中的第3章,第3.7节,作者:(美)Kevin Brothaler ,更多章节内容可以访问云栖社区&qu ...

  8. android开发实现选择列表,Android使用RecyclerView实现列表数据选择操作

    Android使用RecyclerView实现列表数据选择操作 发布时间:2020-08-31 17:50:13 来源:脚本之家 阅读:76 作者:迟做总比不做强 这些时间做安卓盒子项目,因为安卓电视 ...

  9. android之网络请求 -- 获取RecyclerView的列表项(图片 + 文字)

    android之网络请求 -- 获取RecyclerView的列表项 示意图,网络请求的地址,插件及依赖 代码架构 代码内容 MainActivity.java activity_main.xml R ...

最新文章

  1. 网站建设注重用户体验尤为重要
  2. BZOJ1008[HNOI2008]越狱
  3. 首次曝光的计算模型!对标阿里?有没有想过你的中台只是废纸?
  4. 类与对象的演练 好好学习的学生 java 1613807015
  5. iScroll框架的修改
  6. spark shell
  7. cupsd进程_Linux进程基础
  8. 解决wine中文显示为方框的方法
  9. web前端开发和java后端_web前端开发和后端开发的区别是什么
  10. 《老路用得上的商学课》51-55学习笔记
  11. 云计算与大数据复习题
  12. Path.Direction.CCW与Path.Direction.CW的意思
  13. 贝塞尔曲线-曲线拟合
  14. 设计模式之浅浅的理解桥接模式
  15. 什么pdf转换成excel转换器好
  16. 小白重装系统教程_练习如何用u盘重装系统教程
  17. IBM推出区块链食品跟踪网络,零售巨头家乐福参与合作
  18. 一体式风速风向传感器
  19. 计算机房辐射 安全距离,机房辐射范围和预防辐射?
  20. 什么是用户标签?其实很好理解

热门文章

  1. [转]AppCompat 22.1,Goole暴走,MD全面兼容低版本
  2. 基于分时电价策略的家庭能量系统优化(Matlab代码实现)
  3. 润滑剂粘度调节剂的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  4. idea插件translation插件 提示:翻译失败: 未知错误
  5. 我,32岁程序员,三十而立,扛起了整个家
  6. 1、软件项目规划过程——所有表集合
  7. sql显示服务器连接不上,sql服务器连接不上
  8. pyqt5 pyqt5+opencv 实现读取视频数据
  9. office ppt放映时,视频无法播放
  10. 【韩顺平JAVA】房屋出租系统