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

如何原生实现按创建日期分组的List Adapter分段功能?

原生实现RecyclerView分段(按日期分组)的方案

核心思路是给RecyclerView的Adapter定义两种Item类型:分段标题项和普通内容项,通过数据预处理将原始数据按日期分组后,在Adapter中根据位置判断加载对应的布局和数据。

1. 预处理数据,按日期分组

先把原始对象列表按创建日期归类分组,每组包含一个日期标题和对应的对象列表。可以自定义一个Section类来封装分组数据:

// 假设你的原始数据类是DataItem
data class DataItem(val id: String, val content: String, val createTime: Long)

// 分段数据类:包含分组标题和对应的数据列表
data class Section(val dateTitle: String, val items: List<DataItem>)

// 预处理原始数据,按日期分组并排序
fun groupDataByDate(rawList: List<DataItem>): List<Section> {
    return rawList.groupBy {
        // 将时间戳转为yyyy-MM-dd格式的字符串作为分组标识
        SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).format(Date(it.createTime))
    }.entries.sortedByDescending { it.key } // 按日期倒序排列分组
        .map { Section(it.key, it.value) }
}

Java实现逻辑类似,用HashMap完成分组后转成有序列表即可。

2. 定义Adapter的Item类型常量

在Adapter中明确区分两种Item类型:

private val TYPE_SECTION_HEADER = 0
private val TYPE_CONTENT_ITEM = 1

3. 重写Adapter核心方法

3.1 计算总Item数量

总Item数 = 所有分段的标题数 + 所有内容项的数量:

override fun getItemCount(): Int {
    return sections.sumOf { 1 + it.items.size } // 每个分段占1个标题位,加上内容项数量
}

3.2 判断当前位置的Item类型

遍历分组数据,判断当前位置属于标题还是内容项:

override fun getItemViewType(position: Int): Int {
    var currentPos = 0
    for (section in sections) {
        // 检查是否是当前分段的标题
        if (currentPos == position) {
            return TYPE_SECTION_HEADER
        }
        currentPos++
        // 检查是否在当前分段的内容项范围内
        if (position < currentPos + section.items.size) {
            return TYPE_CONTENT_ITEM
        }
        currentPos += section.items.size
    }
    return TYPE_CONTENT_ITEM
}

3.3 创建对应类型的ViewHolder

根据Item类型加载不同布局:

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
    return if (viewType == TYPE_SECTION_HEADER) {
        // 加载分段标题布局
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_section_header, parent, false)
        SectionHeaderViewHolder(view)
    } else {
        // 加载原有内容项布局
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_content, parent, false)
        ContentItemViewHolder(view)
    }
}

3.4 绑定数据到ViewHolder

根据位置找到对应的分组和数据项,完成绑定:

override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
    var currentPos = 0
    for (section in sections) {
        // 绑定分段标题
        if (currentPos == position) {
            (holder as SectionHeaderViewHolder).tvDate.text = section.dateTitle
            return
        }
        currentPos++
        // 绑定内容项
        if (position < currentPos + section.items.size) {
            val contentIndex = position - currentPos
            val item = section.items[contentIndex]
            (holder as ContentItemViewHolder).bind(item)
            return
        }
        currentPos += section.items.size
    }
}

4. 实现ViewHolder类

分别定义标题和内容项的ViewHolder:

class SectionHeaderViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    val tvDate: TextView = itemView.findViewById(R.id.tv_section_date)
}

class ContentItemViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    fun bind(item: DataItem) {
        // 复用你原有内容项的绑定逻辑
        itemView.findViewById<TextView>(R.id.tv_content).text = item.content
    }
}

5. 优化建议

  • 大数据量场景下,建议提前缓存每个分段的起始位置(比如用List<Int>存储所有标题的位置索引),避免每次遍历分组列表,提升性能。
  • 可以把日期标题优化为"今天"、"昨天"这类更友好的文本,只需在分组时增加时间判断逻辑。
  • 数据更新时,重新执行分组逻辑后调用notifyDataSetChanged()(或更精准的局部刷新方法)即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 06:35:31