栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 移动开发 > Android

Kotlin封装RecyclerView Adapter实例教程

Android 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Kotlin封装RecyclerView Adapter实例教程

前言

Kotlin越来越流行,在Google的推动下发展的很迅猛,现在的项目大多使用上了Kotlin,其简练的语法糖确实能减少不少代码。

Adapter的封装GitHub上有很多了,但大多数封装的太好了,是的,使用太简单了,使用简单、封装力度大就导致灵活性和代码复杂性上升,谁用谁知道,当然也有封装简单的。

这里我借助Kotlin的简单语法再次操刀封装了一下。

先看下使用

单类型的使用

val adapter=recyclerView.setUp(users, R.layout.item_layout, { holder, item ->
   var binding = DataBindingUtil.getBinding(holder.itemView)
   binding.nameText.text = item.name
   ...
  })

多类型的使用

recyclerView.setUP(users,
    listItems = *arrayOf(
      ListItem(R.layout.item_layout, { holder, item ->
var binding = DataBindingUtil.getBinding(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 constructor(protected var itemList: List)
 : RecyclerView.Adapter() {

 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) {
  updateAdapterWithDiffResult(calculateDiff(items))
 }

 private fun updateAdapterWithDiffResult(result: DiffUtil.DiffResult) {
  result.dispatchUpdatesTo(this)
 }

 private fun calculateDiff(newItems: List) =
   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()

  fun  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(items: List,
private val layoutResId: Int,
private val bindHolder: (Holder, ITEM) -> Unit)
 : AbstractAdapter(items) {

 private var itemClick: (ITEM) -> Unit = {}

 constructor(items: List,
    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(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(private val items: List,
   private val bindHolder: (Holder, ITEM) -> Unit)
 : AbstractAdapter(items) {

 private var itemClick: (ITEM) -> Unit = {}
 private lateinit var listItems: Array>

 constructor(items: List,
    listItems: Array>,
    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(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  RecyclerView.setUp(items: List,
 layoutResId: Int,
 bindHolder: (AbstractAdapter.Holder, ITEM) -> Unit,
 itemClick: (ITEM) -> Unit = {},
 manager: RecyclerView.LayoutManager = LinearLayoutManager(this.context)): AbstractAdapter {
 val singleAdapter by lazy {
  SingleAdapter(items, layoutResId, { holder, item ->
   bindHolder(holder, item)
  }, {
   itemClick(it)
  })
 }
 layoutManager = manager
 adapter = singleAdapter
 return singleAdapter
}


fun  RecyclerView.setUP(items: List,
    manager: RecyclerView.LayoutManager = LinearLayoutManager(this.context),
    vararg listItems: ListItem): AbstractAdapter {

 val multiAdapter by lazy {
  MultiAdapter(items, listItems, { holder, item ->
   var listItem: ListItem? = getListItem(listItems, item)
   listItem?.bindHolder?.invoke(holder, item)
  }, { item ->
   var listItem: ListItem? = getListItem(listItems, item)
   listItem?.itemClick?.invoke(item)
  })
 }
 layoutManager = manager
 adapter = multiAdapter
 return multiAdapter
}

private fun  getListItem(listItems: Array>, item: ITEM): ListItem? {
 var listItem: ListItem? = null
 listItems.forEach {
  if (it.layoutResId == item.getType()) {
   listItem = it
   return@forEach
  }
 }
 return listItem
}

class ListItem(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(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(holder.itemView)
      }, {//点击事件
Snackbar.make(window.decorView, it.name, Snackbar.LENGTH_SHORT).show()
      })

是不是一样可以的 只要定义到一个地方 然后设置进去就可以了,复用也是难不倒它的。只能说Kotlin语法大法好。

好了,这个库就介绍到这里了,谢谢大家。

代码地址

参考链接

灵感来自下面这位大神,但是我基本重写了

https://github.com/armcha/Kadapter

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对考高分网的支持。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/155627.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号