You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Kotlin中实现基于列表的分组RecyclerView,按Data模型子类型分区

Kotlin 实现按子类型分组的 Sectioned RecyclerView 方案

1. 定义多类型列表项结构

首先用密封类封装两种列表项类型,区分分区头部和业务内容子项:

sealed class SectionedItem {
    // 分区头部项,存储分组名
    data class Header(val groupName: String) : SectionedItem()
    // 业务内容项,存储你原有的数据模型,YourDataModel替换为实际业务模型类
    data class Content(val originData: YourDataModel) : SectionedItem()
}

2. 原始列表按子类型分组拼装

用Kotlin内置的groupBy扩展方法,按你需要的业务字段(比如数据模型的type子类型字段)分组,再拼装成包含头部和内容的混合列表:

// originalDataList为你原有的业务数据列表,按type字段分组得到分组Map
val groupedData = originalDataList.groupBy { it.type }

// 拼装成适配Adapter的混合列表
val sectionedList = mutableListOf<SectionedItem>()
groupedData.forEach { (groupType, dataList) ->
    // 每个分组先添加头部项
    sectionedList.add(SectionedItem.Header(groupType))
    // 再添加该分组下的所有业务内容项
    dataList.mapTo(sectionedList) { SectionedItem.Content(it) }
}

3. 实现多类型RecyclerView.Adapter

重写getItemViewType区分两种布局,分别绑定头部和内容数据:

class SectionedAdapter(private val dataList: List<SectionedItem>) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
    // 定义两种View类型常量
    private companion object {
        const val VIEW_TYPE_HEADER = 0
        const val VIEW_TYPE_CONTENT = 1
    }

    override fun getItemViewType(position: Int): Int {
        return when (dataList[position]) {
            is SectionedItem.Header -> VIEW_TYPE_HEADER
            is SectionedItem.Content -> VIEW_TYPE_CONTENT
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        return when (viewType) {
            VIEW_TYPE_HEADER -> {
                val view = inflater.inflate(R.layout.item_section_header, parent, false)
                HeaderViewHolder(view)
            }
            VIEW_TYPE_CONTENT -> {
                val view = inflater.inflate(R.layout.item_section_content, parent, false)
                ContentViewHolder(view)
            }
            else -> throw IllegalArgumentException("不支持的View类型")
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (val item = dataList[position]) {
            is SectionedItem.Header -> (holder as HeaderViewHolder).bind(item.groupName)
            is SectionedItem.Content -> (holder as ContentViewHolder).bind(item.originData)
        }
    }

    override fun getItemCount(): Int = dataList.size

    // 分区头部ViewHolder
    inner class HeaderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(groupName: String) {
            // 这里替换为你头部布局的实际控件ID,绑定分组名
            itemView.findViewById<TextView>(R.id.tv_header_name).text = groupName
        }
    }

    // 业务内容ViewHolder
    inner class ContentViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        fun bind(data: YourDataModel) {
            // 按业务需求绑定内容数据到布局控件
        }
    }
}

4. 可选功能扩展

  • 如果需要实现分区展开/收起功能,可以在Header类中新增isExpanded: Boolean字段,拼装列表时过滤掉收起分组的Content项,点击头部时更新状态后刷新列表即可
  • 列表数据变更时配合DiffUtil做增量更新,避免全量刷新导致的卡顿
  • 需要自定义分区间距/分割线的话,可以自定义ItemDecoration,判断当前项和前一项的类型是否不同,来针对性添加分割样式

内容的提问来源于stack exchange,提问作者Mohamed Farah

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 18:06:01