Skip to content

Latest commit

 

History

History
104 lines (88 loc) · 3.82 KB

文章.md

File metadata and controls

104 lines (88 loc) · 3.82 KB

前言

在项目开发中,总离不开列表,说到列表,就会有无穷无尽的 Adapter 需要你去实现。从而出现了很多优秀的 adapter 库。 不过很多库功能都很全面了,有很多个类,很多功能,但是实际上只用其中的一两个我感觉是很多人的现状。所以自己实现一个是一个不错的 选择,特别是用在一些不是很复杂的列表时。

效果

先祭出使用效果,激发一下你继续阅读的激情:

//单类型列表
recycleView.setup<NumberInfo> {
    dataSource(initData())
    adapter {
        addItem(R.layout.layout_item) {
            isForViewType { it != null }
            bindViewHolder { data, _, _ ->
                setText(R.id.number, data?.number.toString())
            }
        }
    }
}

//多类型列表
recycleView.setup<Any> {
    withLayoutManager { LinearLayoutManager(context) }
    adapter {
        addItem(R.layout.item_setion_header) {
            isForViewType { it is SectionHeader }
            bindViewHolder { data, _, _ ->
                val header = data as SectionHeader
                setText(R.id.section_title, header.title)
            }
        }
        addItem(R.layout.item_user) {
            isForViewType { it is User }
            bindViewHolder { data, _, _ ->
                val user = data as User
                setText(R.id.name, user.name)
                setImageResource(R.id.avatar, user.avatarRes)
                //如果你的控件找不到方便赋值的方法,可以通过 findViewById 去查找
                val phone = findViewById<TextView>(R.id.phone)
                phone.text = user.phone
            }
        }
    }
}
recycleView.submitList(data)

嗯....,感觉还可以,最少的情况下可以把一个列表代码用 10 级行就完成了。

完整代码地址

没地址说个蛋,先贴完整代码地址:EfficientAdapter
我把它命名为 EfficientAdapter ,意为高效的意思,事实上它只有 3 个类。
至于如何使用,在地址上已经描述了,所以这篇文章主要是讲一下实现的思路。

实现思路

对 Adapter 的封装,其实无非就是对 Adapter 里面的几个回调方法进行封装罢了,最常用的方法是先定义填充好一个 ViewHolder 列表,然后在各个回调中获取这些 ViewHolder,然后实现逻辑。

那么其中最操蛋的是哪个回调方法的封装呢?我认为是 getItemViewType。事实上你可以在很多框架中看到让你实现获取 ViewType 的回调方法。

一步一步来,先说 ViewHolder 的封装

在 EfficientAdapter 里面,我把 ViewHolder 的封装写成了 BaseViewHolder:

class BaseViewHolder(parent: ViewGroup, resource: Int) : RecyclerView.ViewHolder(
        LayoutInflater.from(parent.context).inflate(resource, parent, false)
)

这就是我的封装,够简单吧。

想什么呢,当然没这么简单,想要在上面使用效果中那样实现 ViewHolder 的具体逻辑,还需要 isForViewType,bindViewHolder 等方法。所以我要定义一个类,去提供这些方法:

abstract class ViewHolderCreator<T> {
    abstract fun isForViewType(data: T?, position: Int): Boolean
    abstract fun getResourceId(): Int
    abstract fun onBindViewHolder(
            data: T?,
            items: MutableList<T>?,
            position: Int,
            holder: ViewHolderCreator<T>
    )

    var itemView: View? = null

    fun registerItemView(itemView: View?) {
        this.itemView = itemView
    }

    fun <V : View> findViewById(viewId: Int): V {
        checkItemView()
        return itemView!!.findViewById(viewId)
    }

    private fun checkItemView() {
        if (itemView == null) {
            throw NullPointerException("itemView is null")
        }
    }
}