You need to enable JavaScript to run this app. 如何在RecyclerView的两类消息Item之间插入日期头布局?
优惠活动
大模型
产品
解决方案
定价
更多

如何在RecyclerView的两类消息Item之间插入日期头布局?

聊天列表插入日期头布局的问题修复方案

核心问题梳理

  • 第一个错误:onCreateViewHolder 参数使用错误。该方法的第二个输入参数是getItemViewType返回的视图类型值,不是列表项位置position,你当前的判断逻辑完全错配,导致视图加载混乱。
  • 第二个错误:getItemViewType 逻辑冲突。你现在的逻辑直接用原有消息的位置返回日期视图类型,相当于把原有的消息项直接替换成了日期头,自然会丢失消息内容。
  • 第三个错误:日期判断逻辑反向。你现在判断当前消息日期和上一条相等时返回日期类型,实际应该是当前消息日期和上一条不相等的时候才需要显示日期头。
  • 第四个错误:数据源没有对应日期项的占位,你没有在消息列表中插入额外的日期数据,直接复用消息的位置返回日期类型,必然会覆盖原有消息。

修复方案(两种可选)

方案1:不修改数据源,在消息布局中内置日期控件

这种方案不需要调整列表结构,实现最简单:

  1. 给item_outgoing_message和item_incoming_message布局的顶部都加一个日期TextView,默认设为GONE隐藏
  2. 删掉你原来加的item_show_time_chat布局和相关视图类型判断,getItemViewType只保留原来的0和1两种类型,区分接收/发送消息
  3. 在onBindViewHolder中加判断:
// 第一条消息永远显示日期
if (position == 0) {
    holder.showDateTv?.visibility = View.VISIBLE
    holder.showDateTv?.text = mChatList[position].getMessageDate()
} else {
    val currentDate = mChatList[position].getMessageDate()
    val lastDate = mChatList[position-1].getMessageDate()
    // 当前日期和上一条不一样时显示日期
    if (currentDate != lastDate) {
        holder.showDateTv?.visibility = View.VISIBLE
        holder.showDateTv?.text = currentDate
    } else {
        holder.showDateTv?.visibility = View.GONE
    }
}

方案2:修改数据源,插入独立的日期项

如果你需要日期头作为完全独立的列表项,用这个方案:

  1. 先给聊天数据封装通用类型,可以用密封类:
sealed class ChatItem {
    data class MessageItem(val chat: Chat) : ChatItem()
    data class DateItem(val date: String) : ChatItem()
}
  1. 初始化列表的时候,对原始消息列表做处理,插入日期项:
val chatItems = mutableListOf<ChatItem>()
var lastDate = ""
mChatList.forEach { chat ->
    val currentDate = chat.getMessageDate()
    if (currentDate != lastDate) {
        chatItems.add(ChatItem.DateItem(currentDate))
        lastDate = currentDate
    }
    chatItems.add(ChatItem.MessageItem(chat))
}
// 把处理后的chatItems作为Adapter的数据源
  1. 调整getItemViewType逻辑:
override fun getItemViewType(position: Int): Int {
    return when(chatItems[position]) {
        is ChatItem.MessageItem -> {
            if((chatItems[position] as ChatItem.MessageItem).chat.getSender() == currentUserID) 1 else 0
        }
        is ChatItem.DateItem -> 2
    }
}
  1. 修正onCreateViewHolder的参数和判断逻辑:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    return when(viewType) {
        1 -> {
            val view = LayoutInflater.from(mContext).inflate(R.layout.item_outgoing_message, parent, false)
            MessageViewHolder(view)
        }
        0 -> {
            val view = LayoutInflater.from(mContext).inflate(R.layout.item_incoming_message, parent, false)
            MessageViewHolder(view)
        }
        else -> {
            val view = LayoutInflater.from(mContext).inflate(R.layout.item_show_time_chat, parent, false)
            DateViewHolder(view)
        }
    }
}
  1. onBindViewHolder根据类型分别绑定即可。

内容的提问来源于stack exchange,提问作者mr. groot

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.19 02:45:03