Android-封装个好用、轻量和通用的原生Adapter基类

基于RecyclerView.Adapter构建该通用适配器,以后其他项目直接拿来用就行~

思考1:

  • adapter功能纯粹,如 '构建复用条目布局' 和 '绑定条目数据' 等。

  • 基类应具备的能力:构建条目布局、绑定数据、设置数据源、数据源的增删改查等。
    思考2:

  • 需继承RecyclerView.ViewHolder抽象类

  • 多布局场景的数据源,应具备区分ItemType能力,所以需定义对应接口
    思考3:泛型相关

  • RecyclerView.ViewHolder的子类:泛型-参数View (更方便获取控件对象,否则只配苦逼地findViewById)

  • 单布局Adapter基类:泛型-数据源类型、泛型-条目布局ViewBinding

  • 多布局Adapter基类:泛型-数据源类型

废话不多说,直接上菜~

1.模块下build.gradle.kts中配置ViewBinding

ini 复制代码
android{
    ...
    buildFeatures {
        ...
        viewBinding = true
    }
}

2.构建BaseViewHolder (继承RecyclerView.ViewHolder)

kotlin 复制代码
class BaseViewHolder<VB : ViewBinding>(var viewBinding: VB) : RecyclerView.ViewHolder(viewBinding.root)

★3. 构建单布局适配器BaseRvAdapter

kotlin 复制代码
/**
 * @author yyf
 * 单布局-基类适配器
 */
abstract class BaseRvAdapter<D,VB: ViewBinding> (var mContext: Context) : RecyclerView.Adapter<BaseViewHolder<VB>>() {

    private val mList = mutableListOf<D>()

    override fun getItemCount(): Int = mList.size

    var listener: ((View, Int) -> Unit)? = null

    fun setOnItemClickListener(listener: ((View, Int) -> Unit)? = null) {
        this.listener = listener
    }

    /*数据设置*/
    fun setData(list: MutableList<D>?) {
        list?.let {
            mList.clear()
            mList.addAll(it)
            notifyDataSetChanged()
        }
    }

    /*数据获取*/
    fun getData(): MutableList<D> {
        return mList
    }

    /*增*/
    fun addData(list: MutableList<D>?) {
        if (list?.isNotEmpty() == true) {
            var start = mList.size
            mList.addAll(list)
            var end = mList.size - 1
            notifyItemRangeChanged(start, end)
        }
    }

    /*删*/
    fun removeData(position: Int) {
        if (position >= 0 && position < mList.size) {
            mList.removeAt(position)
            notifyItemRemoved(position)
        }
    }

    /*改*/
    fun updateData(position: Int, bean: D) {
        if (position >= 0 && position < mList.size) {
            mList[position] = bean
            notifyItemChanged(position)
        }
    }

    /*查*/
    fun getData(position: Int): D? {
        if (position >= 0 && position < mList.size) {
            return mList[position]
        }
        return null
    }
}

4.定义MultiItem接口(数据bean实现该接口,使其具备区分ItemType能力)

kotlin 复制代码
interface MultiItem {
    fun getItemType(): Int
}

5.★ 构建多布局适配器BaseRvMultiAdapter

kotlin 复制代码
/**
 * @author yyf
 * 多布局-基类适配器
 */
abstract class BaseRvMultiAdapter<D : MultiItem> (var mContext: Context) : RecyclerView.Adapter<BaseViewHolder<ViewBinding>>() {

    private val mList = mutableListOf<D>()

    override fun getItemCount(): Int = mList.size

    var listener: ((View, Int) -> Unit)? = null

    fun setOnItemClickListener(listener: ((View, Int) -> Unit)? = null) {
        this.listener = listener
    }

    /*数据设置*/
    fun setData(list: MutableList<D>?) {
        list?.let {
            mList.clear()
            mList.addAll(it)
            notifyDataSetChanged()
        }
    }

    /*数据获取*/
    fun getData(): MutableList<D> {
        return mList
    }

    /*增*/
    fun addData(list: MutableList<D>?) {
        if (list?.isNotEmpty() == true) {
            var start = mList.size
            mList.addAll(list)
            var end = mList.size - 1
            notifyItemRangeChanged(start, end)
        }
    }

    /*删*/
    fun removeData(position: Int) {
        if (position >= 0 && position < mList.size) {
            mList.removeAt(position)
            notifyItemRemoved(position)
        }
    }

    /*改*/
    fun updateData(position: Int, bean: D) {
        if (position >= 0 && position < mList.size) {
            mList[position] = bean
            notifyItemChanged(position)
        }
    }

    /*查*/
    fun getData(position: Int): D? {
        if (position >= 0 && position < mList.size) {
            return mList[position]
        }
        return null
    }

    override fun getItemViewType(position: Int): Int {
        return mList[position].getItemType()
    }
}

干货上齐了,大家亲自尝尝看吧~

--------------------------------------------------- ---------------------------------------------------

以下使用示例可忽略了,没啥看的!

举个栗子:

UI布局 activity_main.xml

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/mListRv"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

条目布局 item_test.xml

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:gravity="center"
    android:background="#80000000"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/mName2Tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="name" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="-" />

    <TextView
        android:id="@+id/mValue2Tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="value" />

</LinearLayout>

条目布局 item2_test.xml

xml 复制代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp"
    android:gravity="center"
    android:orientation="horizontal">

    <TextView
        android:id="@+id/mNameTv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="name" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="-" />

    <TextView
        android:id="@+id/mValueTv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="value" />

</LinearLayout>

单布局BaseRvAdapter的使用

kotlin 复制代码
/**
 * @author yyf
 * 单布局尝试
 */
class TestNewAdapter(context: Context) : BaseRvAdapter<TestBean, ItemTestBinding>(context) {
    override fun onCreateViewHolder(
        parent: ViewGroup, viewType: Int
    ): BaseViewHolder<ItemTestBinding> {
        return BaseViewHolder<ItemTestBinding>(ItemTestBinding.inflate(LayoutInflater.from(mContext), parent, false))
    }

    override fun onBindViewHolder(
        holder: BaseViewHolder<ItemTestBinding>,
        position: Int
    ) {
        getData()[position].let {
            holder.viewBinding.mNameTv.text = it.name
            holder.viewBinding.mValueTv.text = it.value

            holder.viewBinding.root.setOnClickListener {
                listener?.invoke(it, position)
            }
        }
    }
}

多布局BaseRvMultiAdapter的使用

kotlin 复制代码
/**
 * @author yyf
 * 多布局尝试
 */
class TestNewMultiAdapter(context: Context) : BaseRvMultiAdapter<TestBean>(context) {
    override fun onCreateViewHolder(
        parent: ViewGroup, viewType: Int
    ): BaseViewHolder<ViewBinding> {
        when (viewType) {
            0 -> {
                return BaseViewHolder<ViewBinding>(ItemTestBinding.inflate(LayoutInflater.from(mContext), parent, false))
            }
            1 -> {
                return BaseViewHolder<ViewBinding>(Item2TestBinding.inflate(LayoutInflater.from(mContext), parent, false))
            }
        }
        return BaseViewHolder<ViewBinding>(ItemTestBinding.inflate(LayoutInflater.from(mContext), parent, false))
    }

    override fun onBindViewHolder(
        holder: BaseViewHolder<ViewBinding>,
        position: Int
    ) {
        getData()[position].let { bean->
            when (getItemViewType(position)) {
                0 -> {
                    (holder.viewBinding as ItemTestBinding).mNameTv.text = bean.name
                    (holder.viewBinding as ItemTestBinding).mValueTv.text = bean.value
                }
                1 -> {
                    (holder.viewBinding as Item2TestBinding).mName2Tv.text = bean.name
                    (holder.viewBinding as Item2TestBinding).mValue2Tv.text = bean.value
                }
            }
            holder.viewBinding.root.setOnClickListener {
                listener?.invoke(it, position)
            }
        }

    }
}

UI层调用

kotlin 复制代码
class MainActivity : ComponentActivity() {

    val viewBinding by lazy { ActivityMainBinding.inflate(LayoutInflater.from(this@MainActivity)) }

    //    val mAdapter by lazy { TestNewAdapter(this@MainActivity) } //单布局适配器
    val mAdapter by lazy { TestNewMultiAdapter(this@MainActivity) } //多布局适配器
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(viewBinding.root)

        viewBinding.mListRv.layoutManager = LinearLayoutManager(this@MainActivity)
        viewBinding.mListRv.adapter = mAdapter
        mAdapter.setOnItemClickListener { view, position ->
            Toast.makeText(this@MainActivity, "点击了 position=$position", Toast.LENGTH_SHORT).show()
        }

        requestData()

    }

    private fun requestData() {
        var list = mutableListOf<TestBean>()
        for (index in 0 until 30) {
            var bean = TestBean()
            bean.name = "name $index"
            bean.value = "value $index"
            bean.type = index % 2
            list.add(bean)
        }
        mAdapter.setData(list)
    }
}
相关推荐
二流小码农2 小时前
鸿蒙开发:独立开发者的烦恼之icon图标选择
android·ios·harmonyos
独自破碎E2 小时前
BISHI43 讨厌鬼进货
android·java·开发语言
右手吉他2 小时前
Hostapd系统源代码学习
android
智先森zhi2 小时前
实战:将 Android 多Module应用迁移到 kmp+cmp
android·ios·kotlin
2501_937145414 小时前
IPTV电视源码系统2026优化版:技术升级,全场景流畅适配
android·电视盒子·源代码管理
Ehtan_Zheng4 小时前
让你的代码更整洁:10 个必知的 Kotlin 扩展函数
android
城东米粉儿5 小时前
Android VSync 笔记
android
城东米粉儿5 小时前
Android SurfaceFlinger 笔记
android