Kotlin - RecycleView.Adapter结合DataBinding封装

自带头部,底部,和空布局的recycleView.Adapter基类封装相关说明:

1.适用于多种类型的条目类型(目前支持头部,底部,和空布局,其他条目布局需要自己扩展)
2.支持空页面展示和自定义空布局
3.支持头部和底部的添加和自定义头部和底部布局

下面对关键代码进行分析:

重写getItemViewType(position: Int) 方法,根据不同的条目返回对应的布局类型在这里我定义了四种布局类型:默认条目类型,头部,底部,和空布局

override fun getItemViewType(position: Int) : Int {
    var head = 0
    if (isHeader) ++head
    if (isFooter) ++head
    if (isHeader && data.isNotEmpty() && position == 0) return headerType                   //数据为空时 头部不显示 若要头部显示,去除空判断
    if (isFooter && data.isNotEmpty() && data.size+head == position+1) return footerType    //数据为空时 尾部不显示 若要尾部显示,去除空判断
    if (isShowEmptyView && data.isEmpty()) return emptyViewType
    return super.getItemViewType(position)
}

重写 getItemCount()方法,计算出需要的 item 数量,这里我在这里我通过判断data数据源的数据来判断当数据为空时不显示头部和底部,有需要显示的可以修改这部分代码

override fun getItemCount(): Int {
    var size = 0
    if (isHeader && data.isNotEmpty()) ++size   //数据为空时 头部不显示 若要头部显示,去除空判断
    if (isFooter && data.isNotEmpty()) ++size   //数据为空时 尾部不显示 若要尾部显示,去除空判断
    val len = data.size
    if (isShowEmptyView && len == 0) return 1
    return len+size
}

重写onCreateViewHolder(parent: ViewGroup, viewType: Int), 根据viewType来判断创建不同的ViewHolder类型,这里头部,底部和空页面都通过了方法返回的方式来创建View,目的是为了方便自定义布局的使用(注意:头部和底部要放到空页面的前面判断,后面会有说明

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    return when(viewType) {
        headerType -> headerViewCreate(parent)
        footerType -> footViewCreate(parent)
        emptyViewType -> emptyViewCreate(parent)
        else -> ViewHolder<D>(DataBindingUtil.inflate<ViewDataBinding>(
            LayoutInflater.from(parent.context),
            layoutResId(),
            parent,
            false).root)
    }
}
    /**
     * 更换头部部布局重写此方法 其他方法类似
     */
    open fun headerViewCreate(parent:ViewGroup):ViewHolderHeader<ViewHeadBinding>{
    return ViewHolderHeader(DataBindingUtil.inflate<ViewHeadBinding>(
        LayoutInflater.from(parent.context),
        R.layout.view_head,
        parent,
        false).root)
}

重写onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) 方法,在该方法中判断布局类型,onBindView 是通用默认的类型,onBindViews适用于头部,底部和空页面布局,大家可以根据自己的需要去改。当然如果有头部布局显示,不要忘记position要减去1。头部,底部的viewHolder 要在空布局的viewHolder之前判断,下面我会贴出原因:

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    when (holder) {
        is ViewHolder<*> -> {
            val i = if (isHeader) position-1 else position
            onBindView(holder.binding as D, data[i], i)
            checkClickListener(holder.binding as D, i)
            holder.binding.executePendingBindings()
        }
        is ViewHolderHeader<*> -> {
            onBindViews(holder.binding)
            holder.binding.executePendingBindings()
        }
        is ViewHolderFooter<*> -> {
            onBindViews(holder.binding)
            holder.binding.executePendingBindings()
        }
        is ViewHolderEmpty<*> -> {
            onBindViews(holder.binding)
            holder.binding.executePendingBindings()
        }
    }
}
    //原因
    open class ViewHolderEmpty<E :ViewDataBinding>(@NonNull itemView: View):  RecyclerView.ViewHolder(itemView){
        var binding : E = DataBindingUtil.getBinding(this.itemView)!!
    }
    class ViewHolderHeader<E : ViewDataBinding>(@NonNull itemView: View): ViewHolderEmpty<E>(itemView)
    class ViewHolderFooter<E : ViewDataBinding>(@NonNull itemView: View): ViewHolderEmpty<E>(itemView)

最后附上完整的代码,希望对大家有帮助,如果有不足的地方欢迎大家指正,谢谢。

abstract class BaseRecycleViewAdapter<T,D : ViewDataBinding>(protected val data:MutableList<T>):RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val emptyViewType   = 1 //空页面
private val headerType      = 2
private val footerType      = 3
private var isUseDefaultListener = true
private var isShowEmptyView      = true
private var isHeader = false
private var isFooter = false

private var onItemClickListener:OnItemClickListener ?= null

constructor(data:MutableList<T>, isUseDefaultListener:Boolean):this(data) {
    this.isUseDefaultListener = isUseDefaultListener
}

constructor(data: MutableList<T>,isUseDefaultListener: Boolean,isShowEmptyView:Boolean, isHeader:Boolean,isFooter:Boolean):this(data,isUseDefaultListener) {
    this.isShowEmptyView = isShowEmptyView
    this.isHeader = isHeader
    this.isFooter = isFooter
}

fun addOnItemClickListener(onItemClickListener: OnItemClickListener) {
    this.onItemClickListener = onItemClickListener
}

@LayoutRes
abstract fun layoutResId(): Int

abstract fun onBindView(binding: D, item:T?, position: Int)

/**
 * 头部,底部和空布局数据展示在此方法中
 * 空布局要放在头部和底部后面
 */
open fun onBindViews(binding: ViewDataBinding) {}

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    return when(viewType) {
        headerType -> headerViewCreate(parent)
        footerType -> footViewCreate(parent)
        emptyViewType -> emptyViewCreate(parent)
        else -> ViewHolder<D>(DataBindingUtil.inflate<ViewDataBinding>(
            LayoutInflater.from(parent.context),
            layoutResId(),
            parent,
            false).root)
    }
}

/**
 * 更换头部布局重写此方法
 */
open fun headerViewCreate(parent: ViewGroup):ViewHolderHeader<ViewHeadBinding>{
    return ViewHolderHeader(DataBindingUtil.inflate<ViewHeadBinding>(
        LayoutInflater.from(parent.context),
        R.layout.view_head,
        parent,
        false).root)
}

/**
 * 更换底部布局重写此方法
 */
open fun footViewCreate(parent: ViewGroup):ViewHolderFooter<ViewFootBinding>{
    return ViewHolderFooter(DataBindingUtil.inflate<ViewFootBinding>(
        LayoutInflater.from(parent.context),
        R.layout.view_foot,
        parent,
        false).root)
}

/**
 * 更换空布局重写此方法
 */
open fun emptyViewCreate(parent: ViewGroup):ViewHolderEmpty<ViewEmptyBinding>{
    return ViewHolderEmpty(DataBindingUtil.inflate<ViewEmptyBinding>(
        LayoutInflater.from(parent.context),
        R.layout.view_empty,
        parent,
        false).root)
}

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    when (holder) {
        is ViewHolder<*> -> {
            val i = if (isHeader) position-1 else position
            onBindView(holder.binding as D, data[i], i)
            checkClickListener(holder.binding as D, i)
            holder.binding.executePendingBindings()
        }
        is ViewHolderHeader<*> -> {
            onBindViews(holder.binding)
            holder.binding.executePendingBindings()
        }
        is ViewHolderFooter<*> -> {
            onBindViews(holder.binding)
            holder.binding.executePendingBindings()
        }
        is ViewHolderEmpty<*> -> {
            onBindViews(holder.binding)
            holder.binding.executePendingBindings()
        }
    }
}

/**
 * 默认添加item点击事件
 */
open fun checkClickListener(binding: D,position: Int) {
    if (isUseDefaultListener && null != onItemClickListener) {
        binding.root.setOnClickListener {
            onItemClickListener!!.onItemClickListener(binding.root,position)
        }
    }
}


/**
 * 返回条目数量
 */
override fun getItemCount(): Int {
    var size = 0
    if (isHeader && data.isNotEmpty()) ++size   //数据为空时 头部不显示 若要头部显示,去除空判断
    if (isFooter && data.isNotEmpty()) ++size   //数据为空时 尾部不显示 若要尾部显示,去除空判断
    val len = data.size
    if (isShowEmptyView && len == 0) return 1
    return len+size
}

/**
 * 返回item类型
 * 添加新的类型重写此方法
 */
override fun getItemViewType(position: Int): Int {
    var head = 0
    if (isHeader) ++head
    if (isFooter) ++head
    if (isHeader && data.isNotEmpty() && position == 0) return headerType                   //数据为空时 头部不显示 若要头部显示,去除空判断
    if (isFooter && data.isNotEmpty() && data.size+head == position+1) return footerType    //数据为空时 尾部不显示 若要尾部显示,去除空判断
    if (isShowEmptyView && data.isEmpty()) return emptyViewType
    return super.getItemViewType(position)
}


open class ViewHolder<D :ViewDataBinding>(@NonNull itemView: View): RecyclerView.ViewHolder(itemView) {
    var binding : D = DataBindingUtil.getBinding(this.itemView)!!
}

open class ViewHolderEmpty<E :ViewDataBinding>(@NonNull itemView: View):  RecyclerView.ViewHolder(itemView){
    var binding : E = DataBindingUtil.getBinding(this.itemView)!!
}
class ViewHolderHeader<E : ViewDataBinding>(@NonNull itemView: View): ViewHolderEmpty<E>(itemView)
class ViewHolderFooter<E : ViewDataBinding>(@NonNull itemView: View): ViewHolderEmpty<E>(itemView)
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容