开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 3 天,点击查看活动详情
我们在Android应用开发中,列表控件RecyclerView基本每个项目都用到,那么你都怎么实现的呢?有人说,我用系统最原始的方式。No problem(没有问题),只要你不嫌麻烦。我一般使用BaseRecyclerViewAdapterHelper,闲话不多说,开始介绍用法。 首先要settings.gradle添加代码
dependencyResolutionManagement {
repositories {
maven {
url "https://jitpack.io"
}
}
}
然后在app模块的build.gradle添加代码
dependencies {
implementation 'com.github.CymChad:BaseRecyclerViewAdapterHelper:3.0.10'
}
单类型BaseQuickAdapter
package com.example.myapplication.adapter
import com.chad.library.adapter.base.BaseQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.example.myapplication.R
import com.example.myapplication.entity.Entity
class SampleQuickAdapter : BaseQuickAdapter<Entity, BaseViewHolder>(R.layout.layout_normal_item) {
override fun convert(holder: BaseViewHolder, item: Entity) {
holder.setText(R.id.tv_text, item.text)
}
}
单类型的列表是最简单的一种,首先需要继承BaseQuickAdapter,指定泛型类型Entity和BaseViewHolder,简单布局一般就使用BaseViewHolder就好,然后在构造方法中传入布局,重写convert()方法设置条目的数据。最后调用adapter.setList()方法设置数据。
<?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="wrap_content"
android:orientation="horizontal"
android:background="#FFF"
android:padding="@dimen/dp_10">
<TextView
android:id="@+id/tv_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
布局很简单,不用多说。
多类型BaseMultiItemQuickAdapter
package com.example.myapplication.adapter
import com.chad.library.adapter.base.BaseMultiItemQuickAdapter
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.example.myapplication.R
import com.example.myapplication.entity.LetterEntity
class SampleMultiItemQuickAdapter : BaseMultiItemQuickAdapter<LetterEntity, BaseViewHolder>() {
init {
addItemType(LetterEntity.ITEM_TYPE_HEAD, R.layout.layout_head_item)
addItemType(LetterEntity.ITEM_TYPE_CONTENT, R.layout.layout_content_item)
}
override fun convert(holder: BaseViewHolder, item: LetterEntity) {
when (item.itemType) {
LetterEntity.ITEM_TYPE_HEAD -> {
}
LetterEntity.ITEM_TYPE_CONTENT -> {
}
}
}
}
多类型的适配器BaseMultiItemQuickAdapter用于简单的多类型场景。你需要让LetterEntity实现MultiItemEntity接口,然后通过判断Entity的itemType字段来决定显示什么内容。注意不要忘了在构造方法中调用addItemType()方法将所有支持的类型和布局对应起来。这种比如用于字母导航的列表。
多类型加强版BaseProviderMultiAdapter
BaseProviderMultiAdapter用于复杂业务的多类型业务,比如聊天房间界面的消息列表显示。使用BaseProviderMultiAdapter的好处就是要复用Provider。
package com.example.myapplication.adapter
import com.chad.library.adapter.base.BaseProviderMultiAdapter
import com.example.myapplication.R
import com.example.myapplication.entity.ChatMsg
import com.example.myapplication.provider.*
class FriendChatAdapter : BaseProviderMultiAdapter<ChatMsg>() {
init {
addItemProvider(WechatTextOrEmojiProvider(0, R.layout.layout_text_or_emoji_item))
addItemProvider(WechatImgProvider(1, R.layout.layout_img_item))
addItemProvider(WechatVoiceProvider(2, R.layout.layout_voice_item))
addItemProvider(WechatVideoProvider(3, R.layout.layout_video_item))
addItemProvider(WechatRedEnvelopeProvider(4, R.layout.layout_red_envelope_item))
// 好友聊天需要语音/视频通话
addItemProvider(WechatVoiceOrVideoRTCProvider(5, R.layout.layout_voice_or_video_rtc_item))
}
override fun getItemType(list: List<ChatMsg>, position: Int): Int {
return list[position].getMsgType()
}
}
package com.example.myapplication.adapter
import com.chad.library.adapter.base.BaseProviderMultiAdapter
import com.example.myapplication.R
import com.example.myapplication.entity.ChatMsg
import com.example.myapplication.provider.*
class GroupChatAdapter : BaseProviderMultiAdapter<ChatMsg>() {
init {
addItemProvider(WechatTextOrEmojiProvider(0, R.layout.layout_text_or_emoji_item))
addItemProvider(WechatImgProvider(1, R.layout.layout_img_item))
addItemProvider(WechatVoiceProvider(2, R.layout.layout_voice_item))
addItemProvider(WechatVideoProvider(3, R.layout.layout_video_item))
addItemProvider(WechatRedEnvelopeProvider(4, R.layout.layout_red_envelope_item))
}
override fun getItemType(list: List<ChatMsg>, position: Int): Int {
return list[position].getMsgType()
}
}
package com.example.myapplication.provider
import com.chad.library.adapter.base.provider.BaseItemProvider
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.example.myapplication.entity.ChatMsg
/**
* 文字和表情😁。
*/
class WechatTextOrEmojiProvider(override val itemViewType: Int, override val layoutId: Int) : BaseItemProvider<ChatMsg>() {
override fun convert(helper: BaseViewHolder, item: ChatMsg) {
// 通过item判断是自己的还是对方发送的消息
// 然后决定显示左边的界面还是右边的界面
}
}
通过adapter的getItemType()方法的返回值对应provider的itemViewType属性。这种高内聚低耦合的写法将多类型布局用得有点惟妙惟肖的感觉了。
节点类型BaseNodeAdapter
BaseNodeAdapter用于可折叠的列表界面。这种类似于电脑版本QQ的聊天好友列表,也是经常使用到的一种列表界面。
package com.example.myapplication.adapter
import com.chad.library.adapter.base.BaseNodeAdapter
import com.chad.library.adapter.base.entity.node.BaseNode
import com.example.myapplication.provider.BranchNodeProvider
import com.example.myapplication.provider.LeafNodeProvider
import com.example.myapplication.R
import com.example.myapplication.entity.FirstNode
import com.example.myapplication.entity.SecondNode
class SampleNodeAdapter : BaseNodeAdapter() {
init {
addFullSpanNodeProvider(BranchNodeProvider(1, R.layout.layout_node_branch_item))
addNodeProvider(LeafNodeProvider(2, R.layout.layout_node_leaf_item))
}
override fun getItemType(data: List<BaseNode>, position: Int): Int {
val baseNode = data[position]
if (baseNode is FirstNode) {
return 1
}
if (baseNode is SecondNode) {
return 2
}
return 0
}
}
树枝节点的实体类继承BaseExpandNode而树叶节点的实体类则直接继承BaseNode,调用addFullSpanNodeProvider()方法来创建可展开的节点,调用addNodeProvider()方法来创建被展开的内容节点。
package com.example.myapplication.provider
import com.chad.library.adapter.base.entity.node.BaseNode
import com.chad.library.adapter.base.provider.BaseNodeProvider
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.example.myapplication.R
import com.example.myapplication.entity.FirstNode
class BranchNodeProvider(override val itemViewType: Int, override val layoutId: Int) : BaseNodeProvider() {
override fun convert(helper: BaseViewHolder, item: BaseNode) {
if (item is FirstNode) {
helper.setText(R.id.tv_type, item.type)
helper.setText(R.id.tv_name, item.name)
}
}
}
package com.example.myapplication.provider
import com.chad.library.adapter.base.entity.node.BaseNode
import com.chad.library.adapter.base.provider.BaseNodeProvider
import com.chad.library.adapter.base.viewholder.BaseViewHolder
import com.example.myapplication.R
import com.example.myapplication.entity.SecondNode
class LeafNodeProvider(override val itemViewType: Int, override val layoutId: Int) : BaseNodeProvider() {
override fun convert(helper: BaseViewHolder, item: BaseNode) {
if (item is SecondNode) {
helper.setText(R.id.tv_type, item.type)
helper.setText(R.id.tv_name, item.name)
}
}
}
数据的结构如下:
private val nodes = arrayListOf(
FirstNode("树枝节点", "增加掘力值的方法", arrayListOf(
SecondNode("树叶节点", "点赞", null),
SecondNode("树叶节点", "收藏", null),
SecondNode("树叶节点", "评论", null)
))
)
最后通过调用expandOrCollapse()方法来展开和折叠节点条目。
nodeAdapter.setOnItemClickListener { _, _, position ->
nodeAdapter.expandOrCollapse(
position
)
}