自带头部,底部,和空布局的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)
}