自帶頭部,底部投蝉,和空布局的recycleView.Adapter基類封裝相關說明:
1.適用于多種類型的條目類型(目前支持頭部养葵,底部,和空布局瘩缆,其他條目布局需要自己擴展)
2.支持空頁面展示和自定義空布局
3.支持頭部和底部的添加和自定義頭部和底部布局
下面對關鍵代碼進行分析:
重寫getItemViewType(position: Int) 方法关拒,根據(jù)不同的條目返回對應的布局類型在這里我定義了四種布局類型:默認條目類型,頭部庸娱,底部着绊,和空布局
override fun getItemViewType(position: Int) : Int {
var head = 0
if (isHeader) ++head
if (isFooter) ++head
if (isHeader && data.isNotEmpty() && position == 0) return headerType //數(shù)據(jù)為空時 頭部不顯示 若要頭部顯示,去除空判斷
if (isFooter && data.isNotEmpty() && data.size+head == position+1) return footerType //數(shù)據(jù)為空時 尾部不顯示 若要尾部顯示熟尉,去除空判斷
if (isShowEmptyView && data.isEmpty()) return emptyViewType
return super.getItemViewType(position)
}
重寫 getItemCount()方法归露,計算出需要的 item 數(shù)量,這里我在這里我通過判斷data數(shù)據(jù)源的數(shù)據(jù)來判斷當數(shù)據(jù)為空時不顯示頭部和底部臣樱,有需要顯示的可以修改這部分代碼
override fun getItemCount(): Int {
var size = 0
if (isHeader && data.isNotEmpty()) ++size //數(shù)據(jù)為空時 頭部不顯示 若要頭部顯示靶擦,去除空判斷
if (isFooter && data.isNotEmpty()) ++size //數(shù)據(jù)為空時 尾部不顯示 若要尾部顯示,去除空判斷
val len = data.size
if (isShowEmptyView && len == 0) return 1
return len+size
}
重寫onCreateViewHolder(parent: ViewGroup, viewType: Int)雇毫, 根據(jù)viewType來判斷創(chuàng)建不同的ViewHolder類型玄捕,這里頭部,底部和空頁面都通過了方法返回的方式來創(chuàng)建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適用于頭部馍迄,底部和空頁面布局,大家可以根據(jù)自己的需要去改局骤。當然如果有頭部布局顯示攀圈,不要忘記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)
/**
* 頭部,底部和空布局數(shù)據(jù)展示在此方法中
* 空布局要放在頭部和底部后面
*/
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)
}
}
}
/**
* 返回條目數(shù)量
*/
override fun getItemCount(): Int {
var size = 0
if (isHeader && data.isNotEmpty()) ++size //數(shù)據(jù)為空時 頭部不顯示 若要頭部顯示幌缝,去除空判斷
if (isFooter && data.isNotEmpty()) ++size //數(shù)據(jù)為空時 尾部不顯示 若要尾部顯示灸促,去除空判斷
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 //數(shù)據(jù)為空時 頭部不顯示 若要頭部顯示,去除空判斷
if (isFooter && data.isNotEmpty() && data.size+head == position+1) return footerType //數(shù)據(jù)為空時 尾部不顯示 若要尾部顯示涵卵,去除空判斷
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)
}