用Kotlin封裝極簡適配器,今後遠離ViewHolder

做爲一名Android開發者,用過ListView或者RecycleView後想必對ViewHolder再熟悉不過了。ViewHolder 一開始並非 Android 原生提供的,而是在ListView中做爲減小頻繁調用findViewById而引入的,再到後來推出了更好的 RecycleView,直接內置了ViewHolder。不過咱們總歸逃脫不了在寫適配器時寫ViewHolder或者findViewById的命運。android

而如今Kotlin的出現彷佛垂手可得地解決了這個問題。你可能還記得,引入Kotlin後,Activity中能夠直接用佈局文件的Id來使用view,原理能夠看下之前寫過的一篇文章Kotlin直接使用控件ID原理解析,本文就是用這個特性來封裝一個極簡地不須要本身建立ViewHolder的通用RecycleView適配器。bash

通用ViewHolder

首先Kotlin上述特性在普通View中默認是關閉,打開app的build.gradle,啓用實驗性功能:app

android {
...
}

androidExtensions {
    experimental = true
}
複製代碼

而後建立一個通用的ViewHolder,很簡單隻有一行代碼:ide

class CommonViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), LayoutContainer {

        override val containerView: View = itemView
    }
複製代碼

極簡適配器

咱們直接上代碼:佈局

open class BaseRecyclerAdapter<M>(
    @LayoutRes val itemLayoutId: Int, list: Collection<M>? = null,
    bind: (BaseRecyclerAdapter<M>.() -> Unit)? = null
) :
    RecyclerView.Adapter<BaseRecyclerAdapter.CommonViewHolder>() {

    init {
        if (bind != null) {
            apply(bind)
        }
    }

    private var dataList = mutableListOf<M>()

    private var mOnItemClickListener: ((v: View, position: Int) -> Unit)? = null
    private var mOnItemLongClickListener: ((v: View, position: Int) -> Boolean) = { _, _ -> false }

    private var onBindViewHolder: ((holder: CommonViewHolder, position: Int) -> Unit)? = null

    fun onBindViewHolder(onBindViewHolder: ((holder: CommonViewHolder, position: Int) -> Unit)) {
        this.onBindViewHolder = onBindViewHolder
    }

    /** * 填充數據,此操做會清除原來的數據 * * @param list 要填充的數據 * @return true:填充成功並調用刷新數據 */
    fun setData(list: Collection<M>?): Boolean {
        var result = false
        dataList.clear()
        if (list != null) {
            result = dataList.addAll(list)
        }
        return result
    }

    /** * 根據位置獲取一條數據 * * @param position View的位置 * @return 數據 */
    fun getItem(position: Int) = dataList[position]

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CommonViewHolder {
        val itemView = LayoutInflater.from(parent.context).inflate(itemLayoutId, parent, false)
        val viewHolder = CommonViewHolder(itemView)
        itemView.setOnClickListener { mOnItemClickListener?.invoke(it, viewHolder.adapterPosition) }
        itemView.setOnLongClickListener { return@setOnLongClickListener mOnItemLongClickListener.invoke(it, viewHolder.adapterPosition) }
        return viewHolder
    }

    override fun getItemCount() = dataList.size

    override fun onBindViewHolder(holder: CommonViewHolder, position: Int) {
        if (onBindViewHolder != null) {
            onBindViewHolder!!.invoke(holder, position)
        } else {
            bindData(holder, position)
        }
    }

    open fun bindData(holder: CommonViewHolder, position: Int) {

    }

    class CommonViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView), LayoutContainer {

        override val containerView: View = itemView
    }

}
複製代碼

使用

首先建立一個簡單的佈局item_textview.xmlpost

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
          android:id="@+id/textview"
          android:layout_width="match_parent"
          android:layout_height="50dp">

</TextView>
複製代碼

咱們能夠經過繼承這個適配器來建立:gradle

class StringAdapter : BaseRecyclerAdapter<String>(R.layout.item_textview) {

    override fun onBindViewHolder(holder: CommonViewHolder, position: Int) {
        super.onBindViewHolder(holder, position)
        holder.textview.text = getItem(position)
    }
}
複製代碼

也能夠採用相似DSL的形式直接建立:ui

val adapter = BaseRecyclerAdapter<String>(R.layout.item_textview) {
        onBindViewHolder { holder, position ->
            holder.textview.text = getItem(position)
        }
    }
複製代碼
相關文章
相關標籤/搜索