简单封装RecyclerView的适配器
2024-11-01 本文已影响0人
Gxinyu
前言
经常写列表数据并且各种状态刷新或者局部刷新的情况,使用局部刷新可以有效降低列表刷新的性能,最近有时间就自己封装了一套方便使用
接口层
适配器接口可自定义,目前只列了常用的
interface IAdapter<T> {
fun addData(data: MutableList<T>?)
fun loadData(data: MutableList<T>?)
fun getData(): MutableList<T>
fun getItem(position: Int): T?
fun getSelectedPosition(): Int
fun setSelected(position: Int, selected: Boolean? = true)
fun setPlaying(position: Int? = getSelectedPosition(), playing: Boolean? = true)
fun getOnItemClickListener(): OnItemClickListener<T>?
fun setOnItemClickListener(onItemClickListener: OnItemClickListener<T>)
}
代理层
代理层主要是实现接口并代理适配器的实现
/**
* 适配器代理
* 处理数据和监听
*/
class AdapterDelegate<T : BaseItem>(private var adapter: RecyclerView.Adapter<*>) : IAdapter<T> {
companion object {
const val INVALID_INDEX = -1
const val PAYLOAD_PLAYING = "payload_playing"
}
private val dataList: MutableList<T> by lazy {
mutableListOf()
}
private var onItemClickListener: OnItemClickListener<T>? = null
override fun addData(data: MutableList<T>?) {
if (!data.isNullOrEmpty()) {
dataList.addAll(data)
adapter.notifyItemRangeInserted(this.dataList.size - data.size, data.size)
}
}
override fun loadData(data: MutableList<T>?) {
if (!data.isNullOrEmpty()) {
dataList.clear()
dataList.addAll(data)
} else {
dataList.clear()
}
adapter.notifyDataSetChanged()
}
override fun getData(): MutableList<T> {
return dataList
}
override fun getItem(position: Int): T? {
if (position < 0 || position >= dataList.size) {
return null
}
if (dataList.isEmpty()) {
return null
}
return dataList[position]
}
override fun getSelectedPosition(): Int {
for (i in dataList.indices) {
if (dataList[i].isSelected) {
return i
}
}
return INVALID_INDEX
}
override fun setSelected(position: Int, selected: Boolean?) {
if (position >= dataList.size) {
return
}
val lastPosition = getSelectedPosition()
if (position == INVALID_INDEX) {
if (lastPosition != INVALID_INDEX) {
dataList[lastPosition].isSelected = false
adapter.notifyItemChanged(lastPosition)
}
} else {
if (lastPosition != INVALID_INDEX) {
if (position != lastPosition) {
val playing = dataList[lastPosition].isPlaying
dataList[lastPosition].isSelected = false
dataList[lastPosition].isPlaying = false
dataList[position].isSelected = true
adapter.notifyItemChanged(lastPosition)
adapter.notifyItemChanged(position)
}
} else {
dataList[position].isSelected = true
dataList[position].isPlaying = true
adapter.notifyItemChanged(position)
}
}
}
override fun setPlaying(position: Int?, playing: Boolean?) {
if (position == null || position < 0 || position >= dataList.size) {
return
}
if (playing != null) {
dataList[position].isPlaying = playing
adapter.notifyItemChanged(position, PAYLOAD_PLAYING)
}
}
override fun getOnItemClickListener(): OnItemClickListener<T>? {
return this.onItemClickListener
}
override fun setOnItemClickListener(onItemClickListener: OnItemClickListener<T>) {
this.onItemClickListener = onItemClickListener
}
}
抽取公共的适配器
抽取的适配器,既可以作为单类型适配器也可以作为多类型适配器使用,主要的是子类去实现
/**
* 多类型适配器
*/
abstract class BaseMultiAdapter<T : BaseMultiItem> : RecyclerView.Adapter<BaseViewHolder<ViewBinding>>(), AdapterWrapper<T, ViewBinding> {
private val adapterDelegate by lazy {
AdapterDelegate<T>(this)
}
override fun getDelegate(): AdapterDelegate<T> {
return adapterDelegate
}
override fun getItemCount(): Int {
return getData().size
}
override fun getItemViewType(position: Int): Int {
return getData()[position].itemType
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder<ViewBinding> {
val multiItemViewBinding = bindItemView(parent)[viewType] ?: throw IllegalArgumentException("viewType is not exist")
return BaseViewHolder(multiItemViewBinding)
}
override fun onBindViewHolder(holder: BaseViewHolder<ViewBinding>, position: Int) {
bindViewHolder(holder.binding, getData()[position], position)
}
override fun onBindViewHolder(holder: BaseViewHolder<ViewBinding>, position: Int, payloads: MutableList<Any>) {
super.onBindViewHolder(holder, position, payloads)
super.onBindViewHolder(holder, position, payloads)
if (payloads.isNotEmpty()) {
bindViewHolder(holder.binding, getData()[position], position, payloads)
}else {
bindViewHolder(holder.binding, getData()[position], position)
}
}
}
搭配配套的公共数据bean类,也可以根据项目需求自定义
open class BaseMultiItem: Serializable {
var itemType: Int? = null
var isSelected: Boolean = false //是否选中
var isPlaying: Boolean = false //是否正在播放
}
封装层
封装层的目的是抽取适配器中的方法交于代理层去实现
/**
* 适配器封装类
*/
interface AdapterWrapper<T : BaseItem, VH : ViewBinding> : IAdapter<T> {
fun getDelegate(): AdapterDelegate<T>
override fun addData(data: MutableList<T>?) {
getDelegate().addData(data)
}
override fun loadData(data: MutableList<T>?) {
getDelegate().loadData(data)
}
override fun getData(): MutableList<T> {
return getDelegate().getData()
}
override fun getItem(position: Int): T? {
return getDelegate().getItem(position)
}
override fun getSelectedPosition(): Int {
return getDelegate().getSelectedPosition()
}
override fun setSelected(position: Int, selected: Boolean?) {
getDelegate().setSelected(position, selected)
}
override fun setPlaying(position: Int?, playing: Boolean?) {
getDelegate().setPlaying(position, playing)
}
override fun setOnItemClickListener(onItemClickListener: OnItemClickListener<T>) {
getDelegate().setOnItemClickListener(onItemClickListener)
}
override fun getOnItemClickListener(): OnItemClickListener<T>? {
return getDelegate().getOnItemClickListener()
}
/**
* ===============================适配器子类重新或者实现===============================
*/
fun bindItemView(parent: ViewGroup): Map<Int, VH>
fun bindViewHolder(viewBinding: VH, data: T, position: Int) {
viewBinding.root.setOnClickListener {
getDelegate().getOnItemClickListener()?.onItemClick(data, position)
}
}
fun bindViewHolder(viewBinding: VH, data: T, position: Int, payloads: MutableList<Any>) {
viewBinding.root.setOnClickListener {
getDelegate().getOnItemClickListener()?.onItemClick(data, position)
}
}
}
搭配配套的item点击监听器
interface OnItemClickListener<T> {
fun onItemClick(item: T, position: Int)
}
具体使用
bindItemView重写回调绑定类型和ViewBinding,也可以多类型也可以单类型
bindViewHolder根据类型绑定数据,总体还是很简单
class CustomMultiAdapter : BaseMultiAdapter<BaseMultiItem>() {
override fun getItemId(position: Int): Long {
return getData()[position].hashCode().toLong()
}
override fun bindItemView(parent: ViewGroup): Map<Int, ViewBinding> {
//TODO map中存储着itemType和对应的ViewBinding
}
override fun bindViewHolder(viewBinding: ViewBinding, data: BaseMultiItem, position: Int) {
super.bindViewHolder(viewBinding, data, position)
//TODO 根据itemType来绑定数据
}
override fun bindViewHolder(viewBinding: ViewBinding, data: BaseMultiItem, position: Int, payloads: MutableList<Any>) {
super.bindViewHolder(viewBinding, data, position, payloads)
val payload = payloads[0]
//TODO 根据局部刷新的payload来绑定数据
}
}