Open yunshuipiao opened 3 years ago
该库是我目前使用过最好用的 adapter 库,严格的遵循数据驱动,针对使用方便性做了一些扩展。
这一步封装,结合 viewbinding 省去 viewholder 的创建过程。
abstract class ViewBindingDelegate<T, VB : ViewBinding> : ItemViewDelegate<T, ViewBindingViewHolder<VB>>() { override fun onCreateViewHolder( context: Context, parent: ViewGroup ): ViewBindingViewHolder<VB> { return ViewBindingViewHolder(inflateBindingWithGeneric(parent)) } }
ViewHolder 的创建需要传入 layout 对应的binding,这里使用反射生成。
相关反射代码如下:
@JvmName("inflateWithGeneric") fun <VB : ViewBinding> Any.inflateBindingWithGeneric(layoutInflater: LayoutInflater): VB = withGenericBindingClass(this) { clazz -> clazz.getMethod("inflate", LayoutInflater::class.java).invoke(null, layoutInflater) as VB } @JvmName("inflateWithGeneric") fun <VB : ViewBinding> Any.inflateBindingWithGeneric(layoutInflater: LayoutInflater, parent: ViewGroup?, attachToParent: Boolean): VB = withGenericBindingClass(this) { clazz -> clazz.getMethod("inflate", LayoutInflater::class.java, ViewGroup::class.java, Boolean::class.java) .invoke(null, layoutInflater, parent, attachToParent) as VB } @JvmName("inflateWithGeneric") fun <VB : ViewBinding> Any.inflateBindingWithGeneric(parent: ViewGroup): VB = inflateBindingWithGeneric(LayoutInflater.from(parent.context), parent, false) fun <VB : ViewBinding> Any.bindViewWithGeneric(view: View): VB = withGenericBindingClass(this) { clazz -> clazz.getMethod("bind", LayoutInflater::class.java).invoke(null, view) as VB } private fun <VB : ViewBinding> withGenericBindingClass(any: Any, block: (Class<VB>) -> VB): VB { any.allParameterizedType.forEach { parameterizedType -> parameterizedType.actualTypeArguments.forEach { try { return block.invoke(it as Class<VB>) } catch (e: Exception) { } } } throw IllegalArgumentException("There is no generic of ViewBinding.") } private val Any.allParameterizedType: List<ParameterizedType> get() { val genericParameterizedType = mutableListOf<ParameterizedType>() var genericSuperclass = javaClass.genericSuperclass var superclass = javaClass.superclass while (superclass != null) { if (genericSuperclass is ParameterizedType) { genericParameterizedType.add(genericSuperclass) } genericSuperclass = superclass.genericSuperclass superclass = superclass.superclass } return genericParameterizedType }
不使用发射,需要抽象一个方法,将 binding 的实例返回。
abstract class ViewBindingDelegate2<T, VB : ViewBinding> : ItemViewDelegate<T, ViewBindingViewHolder<VB>>() { override fun onCreateViewHolder( context: Context, parent: ViewGroup ): ViewBindingViewHolder<VB> { return ViewBindingViewHolder(binding(parent)) } abstract fun binding(parent: ViewGroup): VB } class ViewBindingViewHolder<VB : ViewBinding>(val binding: VB) : RecyclerView.ViewHolder(binding.root)
这里考虑使用扩展函数,封装进行使用。
abstract class AnyCallback(val oldItems: List<Any>, val newItems: List<Any>) : DiffUtil.Callback() { override fun getOldListSize(): Int { return oldItems.size } override fun getNewListSize(): Int { return newItems.size } override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { val oldItem = oldItems[oldItemPosition] val newItem = newItems[newItemPosition] return areItemsTheSame(oldItem, newItem) } abstract fun areItemsTheSame(oldItem: Any, newItem: Any): Boolean override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean { val oldItem = oldItems[oldItemPosition] val newItem = newItems[newItemPosition] return areContentsTheSame(oldItem, newItem) } abstract fun areContentsTheSame(oldItem: Any, newItem: Any): Boolean } // 带动画的差分更新 fun MultiTypeAdapter.submitList(callback: AnyCallback) { val result = DiffUtil.calculateDiff(callback) items = callback.newItems result.dispatchUpdatesTo(this) } // 旧方法更新 fun MultiTypeAdapter.updateItems(items: List<Any>) { this.items = items notifyDataSetChanged() }
MultiType: https://github.com/drakeet/MultiType
DylanCaiCoding:ViewBindingKTX: https://github.com/DylanCaiCoding/ViewBindingKTX
MultiType 的扩展使用(ViewBinding, Diff.Callback)
该库是我目前使用过最好用的 adapter 库,严格的遵循数据驱动,针对使用方便性做了一些扩展。
Delegate 的封装
这一步封装,结合 viewbinding 省去 viewholder 的创建过程。
使用反射
ViewHolder 的创建需要传入 layout 对应的binding,这里使用反射生成。
相关反射代码如下:
不使用反射
不使用发射,需要抽象一个方法,将 binding 的实例返回。
结合 DiffUtil.Callback 做局部更新
这里考虑使用扩展函数,封装进行使用。
参考资料
MultiType: https://github.com/drakeet/MultiType
DylanCaiCoding:ViewBindingKTX: https://github.com/DylanCaiCoding/ViewBindingKTX