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

标签:kotlin,recyclerview,adapter
0
投稿

猜你喜欢

  • Android 后台发送邮件示例 (收集应用异常信息+Demo代码)

    2022-06-24 16:31:06
  • springboot配置项目启动后自动打开浏览器访问项目方式

    2023-10-05 07:33:09
  • c#动态改变webservice的url访问地址

    2021-10-08 20:13:03
  • Hibernate用ThreadLocal模式(线程局部变量模式)管理Session

    2021-10-01 18:50:10
  • C/C++ Qt TreeWidget 嵌套节点操作使用

    2022-07-10 01:55:59
  • 深入理解C# 装箱和拆箱(整理篇)

    2023-10-04 02:13:13
  • Flutter Future异步操作详细讲解

    2022-04-05 17:55:32
  • Android:“万能”Activity重构篇

    2023-09-19 07:41:05
  • 使用Maven搭建Hadoop开发环境

    2021-09-11 07:55:45
  • SpringMVC 文件上传配置,多文件上传,使用的MultipartFile的实例

    2023-03-25 14:12:43
  • java开发RocketMQ之NameServer路由管理源码分析

    2023-10-27 20:56:12
  • 利用C#实现SSLSocket加密通讯的方法详解

    2023-03-01 02:23:05
  • AlertDialog点击按钮不消失的实现方法

    2023-12-12 07:11:16
  • Android自定义Adapter的ListView的思路及代码

    2023-10-21 17:56:16
  • C#中使用IFormattable实现自定义格式化字符串输出示例

    2023-05-31 23:34:04
  • Java实现删除排序链表中的重复元素的方法

    2022-11-28 08:27:22
  • Java 替换字符串中的回车换行符的方法

    2022-10-05 10:55:22
  • Flutter软键盘的原理浅析

    2023-10-15 11:18:34
  • Java实现五子棋AI算法

    2022-02-23 05:32:57
  • android Handler详细使用方法实例

    2022-11-29 01:35:12
  • asp之家 软件编程 m.aspxhome.com