android开源系统brvah,Android Jetpack之通用Adapter(Databinding+BRVAH)
之前發(fā)過一個databinding版的通用adapter,能實現(xiàn)一般需求,不過功能比較簡陋,實際開發(fā)中大家更傾向于使用BRVAH等功能豐富的第三方框架。現(xiàn)在給出一個基于BRVAH的databinding版通用Adapter。
BaseAdapter
abstract class BaseAdapter
(private val brId: Int, layoutId: Int, dataList: MutableList?)
: BaseQuickAdapter(layoutId, dataList) {
...
}
構造函數(shù)比較長,兩個泛型,T代表item的model類型即dataList的bean類型,TBinding代表itemLayout對應生成的XXXBinding類,比如itemLayout是fruit_item.xml,對應的就是FruitItemBinding。三個個參數(shù)dataList和layoutId應該不用解釋,brId則對應itemLayout里相應variable的變量名,比如variable的name是fruit,brId就是BR.fruit。
數(shù)據(jù)綁定
override fun onItemViewHolderCreated(viewHolder: BaseViewHolder, viewType: Int) {
DataBindingUtil.bind(viewHolder.itemView)
}
final override fun convert(helper: BaseViewHolder, item: T) = convert(helper, item, helper.layoutPosition)
//final override fun convert(helper: BaseViewHolder, item: T, payloads: List) = convert(helper, item, helper.layoutPosition, payloads)
protected open fun convert(holder: BaseViewHolder, item: T, position: Int) {
holder.getBinding()?.apply {
setVariable(brId, item)
executePendingBindings()
}
}
//protected open fun convert(holder: BaseViewHolder, item: T, position: Int, payloads: List) {}
重寫onItemViewHolderCreated方法傳入泛型TBinding,并在convert方法里執(zhí)行綁定。這里暴露了一個重載方法convert(holder: BaseViewHolder, item: T, position: Int)。用過BRVAH的程序猿都知道默認的convert方法里并不提供當前item對應的position,這點不方便導致該框架被問的最多的問題之一就是“如何在convert方法里獲取position” -_-! 這里直接在原來的convert方法里調用新增的重載方法并傳入當前的position,這樣在子類里我們重寫convert方法時就可以直接獲得當前的position了。同時原convert方法被設置為final類型以確保其在子類中不被重寫。
點擊監(jiān)聽擴展
BRVAH默認的setOnItemClickListener有一點不好,就是不提供當前的item,只能通過dataList[position]或adpter.getItem(position) as T來獲取。前者可能需要我們將dataList設置為全局變量,后者更是需要做強制類型轉換,都不是很方便。現(xiàn)在我們丟掉自帶監(jiān)聽,重新實現(xiàn)一個能提供當前item的點擊監(jiān)聽方法。
private var onItemClickListener: ((BaseAdapter, View, Int, T) -> Unit)? = null
private var onItemLongClickListener: ((BaseAdapter, View, Int, T) -> Boolean)? = null
private var onItemChildClickListener: ((BaseAdapter, View, Int, T) -> Unit)? = null
private var onItemChildLongClickListener: ((BaseAdapter, View, Int, T) -> Boolean)? = null
protected open fun setOnItemClick(view: View, position: Int, item: T) {
onItemClickListener?.invoke(this, view, position, item)
}
protected open fun setOnItemLongClick(view: View, position: Int, item: T): Boolean {
return onItemLongClickListener?.invoke(this, view, position, item) ?: false
}
protected open fun setOnItemChildClick(view: View, position: Int, item: T) {
onItemChildClickListener?.invoke(this, view, position, item)
}
protected open fun setOnItemChildLongClick(view: View, position: Int, item: T): Boolean {
return onItemChildLongClickListener?.invoke(this, view, position, item) ?: false
}
fun setOnItemClickListener(listener: (BaseAdapter, View, Int, T) -> Unit) {
onItemClickListener = listener
}
fun setOnItemLongClickListener(listener: (BaseAdapter, View, Int, T) -> Boolean) {
onItemLongClickListener = listener
}
fun setOnItemChildClickListener(listener: (BaseAdapter, View, Int, T) -> Unit) {
onItemChildClickListener = listener
}
fun setOnItemChildLongClickListener(listener: (BaseAdapter, View, Int, T) -> Boolean) {
onItemChildLongClickListener = listener
}
override fun bindViewClickListener(viewHolder: BaseViewHolder, viewType: Int) {
onItemClickListener?.let {
viewHolder.itemView.setOnClickListener { v ->
var position = viewHolder.adapterPosition
if (position == RecyclerView.NO_POSITION) {
return@setOnClickListener
}
position -= headerLayoutCount
setOnItemClick(v, position, getItem(position))
}
}
onItemLongClickListener?.let {
viewHolder.itemView.setOnLongClickListener { v ->
var position = viewHolder.adapterPosition
if (position == RecyclerView.NO_POSITION) {
return@setOnLongClickListener false
}
position -= headerLayoutCount
setOnItemLongClick(v, position, getItem(position))
}
}
onItemChildClickListener?.let {
for (id in getChildClickViewIds()) {
viewHolder.itemView.findViewById(id)?.let { childView ->
if (!childView.isClickable) {
childView.isClickable = true
}
childView.setOnClickListener { v ->
var position = viewHolder.adapterPosition
if (position == RecyclerView.NO_POSITION) {
return@setOnClickListener
}
position -= headerLayoutCount
setOnItemChildClick(v, position, getItem(position))
}
}
}
}
onItemChildLongClickListener?.let {
for (id in getChildLongClickViewIds()) {
viewHolder.itemView.findViewById(id)?.let { childView ->
if (!childView.isLongClickable) {
childView.isLongClickable = true
}
childView.setOnLongClickListener { v ->
var position = viewHolder.adapterPosition
if (position == RecyclerView.NO_POSITION) {
return@setOnLongClickListener false
}
position -= headerLayoutCount
setOnItemChildLongClick(v, position, getItem(position))
}
}
}
}
}
因為一并重寫了長按和子控件的監(jiān)聽所以代碼略有點長,其實只需要看onItemClickListener,setOnItemClick,setOnItemClickListener和bindViewClickListener這四個方法就行了。
首先private var onItemClickListener: ((BaseAdapter, View, Int, T) -> Unit)? = null這里onItemClickListener是一個函數(shù)對象(在kotlin里萬物皆可定義為對象),具體實現(xiàn)在setOnItemClickListener時指定。setOnItemClick相比框架的原版方法多了一個參數(shù)item: T,以便暴露當前的item。然后重寫B(tài)RVAH的bindViewClickListener方法,將原版的setOnItemLongClick方法換成我們修改版的并傳入當前item。
這里順便提一下為什么不用接口來實現(xiàn)監(jiān)聽。在java里我們通常使用接口來實現(xiàn)監(jiān)聽回調,但在kotlin里更推薦將監(jiān)聽接口直接定義為函數(shù)對象,因為kotlin接口不支持轉換為lambda表達式,而函數(shù)對象可以(kotlin調用java接口也可以)。如果要通過接口實現(xiàn)同時又不舍得放棄lambda,則只能將接口寫在外面的java類中。(不想多此一舉的話,還是選擇函數(shù)對象吧)
實現(xiàn)類adapter
class FruitAdapter (layoutId: Int, brId: Int, itemList: MutableList) : BaseAdapter(layoutId, brId, itemList)
一行代碼就搞定了!如果需要執(zhí)行其他操作,就跟用BRVAH一樣重寫convert方法
override fun convert(holder: BaseViewHolder, item: Fruit, position: Int) {
super.convert(holder, item, position) //別忘了調用父類方法,否則不會執(zhí)行綁定
...
}
同時BaseQuickAdapter的其他功能都被保留!
擴展閱讀
總結
以上是生活随笔為你收集整理的android开源系统brvah,Android Jetpack之通用Adapter(Databinding+BRVAH)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 全网最全-固定资本存量分省、市、地区、产
- 下一篇: Robocode 圆周瞄准算法机器人