Android Kotlin实现类WhatsApp聊天界面滚动时显示隐藏日期功能
问题1:高效按日期分组插入日期分隔符
- 先修复你现有代码的Bug:
MESSAGE_COMPARATOR的areContentsTheSame方法里写了oldItem.text == oldItem.text,改为oldItem.text == newItem.text,否则消息内容更新时不会触发列表刷新。 - 首先统一消息列表的排序规则:按时间戳从旧到新排序(如果你的聊天列表是最新消息在底部,最后展示时可以反转列表,或者给RecyclerView设置
reverseLayout=true)。 - 新增消息类型常量
DATE_DIVIDER = 4,专门用来标识日期分隔符,不要和系统消息共用类型。 - 所有列表处理逻辑放在子线程执行:遍历排序后的原始消息列表,对比当前消息和前一条消息的日期(仅精确到天,可通过
SimpleDateFormat格式化为yyyy-MM-dd字符串对比,或用LocalDate实例对比),如果日期不同,就在当前消息前插入一条type为DATE_DIVIDER的Message实例,time字段存储当天的日期字符串。 - 处理完成后再调用
adapter.submitList(处理后的列表),ListAdapter自带的DiffUtil会自动计算增量更新,哪怕万级数据量也不会出现卡顿。
问题2:滚动时动态悬浮显示当前日期标签
- 方案1(实现简单):在RecyclerView的布局外层叠加一个居中悬浮的TextView,样式和日期分隔符保持一致,默认隐藏。
- 给RecyclerView添加
OnScrollListener,每次滚动回调时:- 获取当前可见区域内的第一条非分隔符、非系统消息的位置
- 拿到该消息的日期,用Android自带的
DateUtils类判断是否为今天、昨天,格式化为对应字符串后显示在悬浮TextView上
- 方案2(效果更流畅,和WhatsApp完全一致):自定义
RecyclerView.ItemDecoration,重写onDrawOver方法,直接在RecyclerView上层绘制当前日期标签,同时可以实现新的日期分隔符滚动到顶部时把旧标签顶出去的交互动画,不需要额外加悬浮布局。
问题3:群聊系统提示效果实现
- 新增消息类型常量
SYSTEM_NOTICE = 5,专门用来标识加群、退群等系统消息,不要和日期分隔符共用ViewHolder。 - 新建单独的系统消息布局:背景用半透明灰色圆角,TextView居中,文字用浅灰色,不需要左右对齐的气泡样式。
- 在
getItemViewType方法中判断如果消息type为added,返回SYSTEM_NOTICE类型,绑定数据时直接拼接文案:binding.systemText.text = "${item.name}通过群组邀请链接加入",后续如果有其他系统事件(比如踢人、群名修改)可以扩展type字段对应不同的文案模板。 - 系统消息不需要和普通消息一样显示发送时间、发送人头像,样式和普通消息、日期分隔符明确区分即可。
内容的提问来源于stack exchange,提问作者Compose Learner
相关产品推荐
相关产品推荐

