Kotlin封装RecyclerView Adapter实例教程
作者:蓦然地执着 发布时间:2023-11-06 01:54:23
前言
Kotlin越来越流行,在Google的推动下发展的很迅猛,现在的项目大多使用上了Kotlin,其简练的语法糖确实能减少不少代码。
Adapter的封装GitHub上有很多了,但大多数封装的太好了,是的,使用太简单了,使用简单、封装力度大就导致灵活性和代码复杂性上升,谁用谁知道,当然也有封装简单的。
这里我借助Kotlin的简单语法再次操刀封装了一下。
先看下使用
单类型的使用
val adapter=recyclerView.setUp(users, R.layout.item_layout, { holder, item ->
var binding = DataBindingUtil.getBinding<ItemLayoutBinding>(holder.itemView)
binding.nameText.text = item.name
...
})
多类型的使用
recyclerView.setUP(users,
listItems = *arrayOf(
ListItem(R.layout.item_layout, { holder, item ->
var binding = DataBindingUtil.getBinding<ItemLayoutBinding>(holder.itemView)
binding?.nameText?.text = item.name
...
}, {
Snackbar.make(window.decorView, it.name, Snackbar.LENGTH_SHORT).show()
}),
ListItem(R.layout.item_layout2, { holder, item ->
val nameText: TextView = holder.getView(R.id.nameText)
nameText.text = item.name
...
}, {
})
))
使用就是如此简单,再来看下代码是不是过度封装
Adapter的基类
abstract class AbstractAdapter<ITEM> constructor(protected var itemList: List<ITEM>)
: RecyclerView.Adapter<AbstractAdapter.Holder>() {
override fun getItemCount() = itemList.size
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Holder {
val view = createItemView(parent, viewType)
val viewHolder = Holder(view)
val itemView = viewHolder.itemView
itemView.setOnClickListener {
val adapterPosition = viewHolder.adapterPosition
if (adapterPosition != RecyclerView.NO_POSITION) {
onItemClick(itemView, adapterPosition)
}
}
return viewHolder
}
fun update(items: List<ITEM>) {
updateAdapterWithDiffResult(calculateDiff(items))
}
private fun updateAdapterWithDiffResult(result: DiffUtil.DiffResult) {
result.dispatchUpdatesTo(this)
}
private fun calculateDiff(newItems: List<ITEM>) =
DiffUtil.calculateDiff(DiffUtilCallback(itemList, newItems))
fun add(item: ITEM) {
itemList.toMutableList().add(item)
notifyItemInserted(itemList.size)
}
fun remove(position: Int) {
itemList.toMutableList().removeAt(position)
notifyItemRemoved(position)
}
final override fun onViewRecycled(holder: Holder) {
super.onViewRecycled(holder)
onViewRecycled(holder.itemView)
}
protected open fun onViewRecycled(itemView: View) {
}
protected open fun onItemClick(itemView: View, position: Int) {
}
protected abstract fun createItemView(parent: ViewGroup, viewType: Int): View
class Holder(itemView: View) : RecyclerView.ViewHolder(itemView) {
private val views = SparseArray<View>()
fun <T : View> getView(viewId: Int): T {
var view = views[viewId]
if (view == null) {
view = itemView.findViewById(viewId)
views.put(viewId, view)
}
return view as T
}
}
}
子类的实现和RecyclerView的扩展
class SingleAdapter<ITEM>(items: List<ITEM>,
private val layoutResId: Int,
private val bindHolder: (Holder, ITEM) -> Unit)
: AbstractAdapter<ITEM>(items) {
private var itemClick: (ITEM) -> Unit = {}
constructor(items: List<ITEM>,
layoutResId: Int,
bindHolder: (Holder, ITEM) -> Unit,
itemClick: (ITEM) -> Unit = {}) : this(items, layoutResId, bindHolder) {
this.itemClick = itemClick
}
override fun createItemView(parent: ViewGroup, viewType: Int): View {
var view = parent inflate layoutResId
if (view.tag?.toString()?.contains("layout/") == true) {
DataBindingUtil.bind<ViewDataBinding>(view)
}
return view
}
override fun onBindViewHolder(holder: Holder, position: Int) {
bindHolder(holder, itemList[position])
}
override fun onItemClick(itemView: View, position: Int) {
itemClick(itemList[position])
}
}
class MultiAdapter<ITEM : ListItemI>(private val items: List<ITEM>,
private val bindHolder: (Holder, ITEM) -> Unit)
: AbstractAdapter<ITEM>(items) {
private var itemClick: (ITEM) -> Unit = {}
private lateinit var listItems: Array<out ListItem<ITEM>>
constructor(items: List<ITEM>,
listItems: Array<out ListItem<ITEM>>,
bindHolder: (Holder, ITEM) -> Unit,
itemClick: (ITEM) -> Unit = {}) : this(items, bindHolder) {
this.itemClick = itemClick
this.listItems = listItems
}
override fun createItemView(parent: ViewGroup, viewType: Int): View {
var view = parent inflate getLayoutId(viewType)
if (view.tag?.toString()?.contains("layout/") == true) {
DataBindingUtil.bind<ViewDataBinding>(view)
}
return view
}
private fun getLayoutId(viewType: Int): Int {
var layoutId = -1
listItems.forEach {
if (it.layoutResId == viewType) {
layoutId = it.layoutResId
return@forEach
}
}
return layoutId
}
override fun getItemViewType(position: Int): Int {
return items[position].getType()
}
override fun onBindViewHolder(holder: Holder, position: Int) {
bindHolder(holder, itemList[position])
}
override fun onItemClick(itemView: View, position: Int) {
itemClick(itemList[position])
}
}
fun <ITEM> RecyclerView.setUp(items: List<ITEM>,
layoutResId: Int,
bindHolder: (AbstractAdapter.Holder, ITEM) -> Unit,
itemClick: (ITEM) -> Unit = {},
manager: RecyclerView.LayoutManager = LinearLayoutManager(this.context)): AbstractAdapter<ITEM> {
val singleAdapter by lazy {
SingleAdapter(items, layoutResId, { holder, item ->
bindHolder(holder, item)
}, {
itemClick(it)
})
}
layoutManager = manager
adapter = singleAdapter
return singleAdapter
}
fun <ITEM : ListItemI> RecyclerView.setUP(items: List<ITEM>,
manager: RecyclerView.LayoutManager = LinearLayoutManager(this.context),
vararg listItems: ListItem<ITEM>): AbstractAdapter<ITEM> {
val multiAdapter by lazy {
MultiAdapter(items, listItems, { holder, item ->
var listItem: ListItem<ITEM>? = getListItem(listItems, item)
listItem?.bindHolder?.invoke(holder, item)
}, { item ->
var listItem: ListItem<ITEM>? = getListItem(listItems, item)
listItem?.itemClick?.invoke(item)
})
}
layoutManager = manager
adapter = multiAdapter
return multiAdapter
}
private fun <ITEM : ListItemI> getListItem(listItems: Array<out ListItem<ITEM>>, item: ITEM): ListItem<ITEM>? {
var listItem: ListItem<ITEM>? = null
listItems.forEach {
if (it.layoutResId == item.getType()) {
listItem = it
return@forEach
}
}
return listItem
}
class ListItem<ITEM>(val layoutResId: Int,
val bindHolder: (holder: AbstractAdapter.Holder, item: ITEM) -> Unit,
val itemClick: (item: ITEM) -> Unit = {})
interface ListItemI {
fun getType(): Int
}
ok,所有核心代码,没有了,也不打算发布rar,要用的直接clone下来引入项目,这是最好的方式,因为不复杂,要改随时可以改。
看上面的多类型的使用,可以发现它是支持普通Layout和DataBinding Layout的,这也是本库的一个特色,不需要多余的处理。
1.普通的Layout 这样处理
ListItem(R.layout.item_layout2, { holder, item ->
val nameText: TextView = holder.getView(R.id.nameText)
nameText.text = item.name
}
通过Holder来操作View,里面有做缓存的。
DataBinding Layout
ListItem(R.layout.item_layout, { holder, item ->
var binding = DataBindingUtil.getBinding<ItemLayoutBinding>(holder.itemView)
binding.nameText.text = item.name
}
是不是只要自己知道是哪中Layout,对应处理就可以了,Holder处理方式也是可以处理DataBinding Layout的,要知晓。
这里提下,可能有人会问干嘛不直接用Kotlin的Layout View 查找方法???
那样代码看起来是简单,但是现在的Studio 对这个的支持不是很好,经常报红,程序员看到红会烦躁啊!!如果还是喜欢的话实现也很简单,改成View的扩展返回就可以了,可以自己动手试下哦。
因为这里只是对不变的部分进行了封装,没有很多华丽丽的添加头部、脚部啥的功能,点击事件倒是内置了一种,当然点击事件还可以用ItemTouchHelper实现,都是可以的。
这样每次就不用写一大串的Adaper了,是不是可以开心地泡壶茶,吹口气了。
别的库都可以Item复用的,你的可以吗?
嗯嗯、、?可以的
比如
val item: (AbstractAdapter.Holder, User) -> Unit = { holder, user ->
}
再比如
ListItem(R.layout.item_layout, { holder, item ->
var binding = DataBindingUtil.getBinding<ItemLayoutBinding>(holder.itemView)
}, {//点击事件
Snackbar.make(window.decorView, it.name, Snackbar.LENGTH_SHORT).show()
})
是不是一样可以的 只要定义到一个地方 然后设置进去就可以了,复用也是难不倒它的。只能说Kotlin语法 * 好。
好了,这个库就介绍到这里了,谢谢大家。
代码地址
参考链接
灵感来自下面这位大神,但是我基本重写了
https://github.com/armcha/Kadapter
来源:https://www.jianshu.com/p/d06673a026a5


猜你喜欢
- 对象内存分配与回收策略对象的内存分配,往大方向讲,就是在堆上分配〔但也可能经过JIT编译后被拆散为标量类型并间接地栈上分配),对象主要分配在
- private void dataGridView1_RowsAdded(object sender, DataGridViewRowsAd
- Springboot上传文件时提示405问题描述:上传文件时请求不通,状态码返回405,如下图: 问题分析:405 Method
- HashMap的原理 HashMap的数据结构为数组+链表,以key,value的形式存值,通过调用put与get方法来存值与取值。它内部维
- 本文为大家分享了java组件实现文件上传功能的具体代码,供大家参考,具体内容如下1 SmartUpload上传组件SmartUpload上传
- 综述在Retrofit2.0使用详解这篇文章中详细介绍了retrofit的用法。并且在retrofit中我们可以通过ResponseBody
- 前言在电商的应用中,最常见的就是在首页或完成某事件之后,弹出一堆的活动/广告。假如重叠弹出,很丑,给用户的体验也不好,所以一般都会依次依条件
- 创建类模式主要关注对象的创建过程,将对象的创建过程进行封装,使客户端可以直接得到对象,而不用去关心如何创建对象。创建类模式有5种,分别是:
- Swagger2配置(解决404报错)在spring boot项目中配置Swagger2,配置好了但是访问确实404,SwaggerConf
- 前台处理首先前台先要获取所有的要删除数据的ID,并将ID拼接成字符串 例如: 2,3,4,5,然后通过GET请求返送到后台。后台处理控制器接
- 先说下 需要的依赖包<dependency> <groupId>org.ap
- 前言周六在公司写Reactor模型,一女同事问我为啥都2023年了还在学习Reactor模型呀,我问她为啥快30的年纪了,周六还在公司看我写
- 在java中用到的最多的时间类莫过于 java.util.Date了, 由于Date类中将getYear(),getMonth()等获取年、
- 前言 在软件开发中,我们通常会遇到一种场景,比如某个请求,会依次经过系统中的很多个模块来处理,如果某个模
- Java的外部类为什么不能使用private和protected进行修饰对于这个问题,一直没有仔细思考,今天整理一下:对于顶级类(外部类)来
- 类锁和对象锁是否会冲突?对象锁和私有锁是否会冲突?通过实例来进行说明。一、相关约定为了明确后文的描述,先对本文涉及到的锁的相关定义作如下约定
- java中 Set与Map排序输出到Writer详解及实例一般来说java.util.Set,java.util.Map输出的内
- 前言集合是Java开发日常开发中经常会使用到的。关于集合类,《阿里巴巴Java开发手册》中其实还有另外一个规定:本文就来分析一下为什么会有如
- 什么是POM?POM是项目对象模型(Project Object Model)的简称,它是Maven项目中的文件,使用XML表示,名称叫做p
- 本文实例为大家分享了Unity3d简易五子棋源码,供大家参考,具体内容如下Unity3d部分对C#源码进行了改写简化:using Unity