Android(Compose)
组件概述
MessageList 是一个基于 Jetpack Compose 构建的消息列表组件,主要用于展示和管理聊天消息。该组件提供了完整的消息类型展示功能:
消息类型支持:文本、图片、视频、语音、文件、表情、合并转发、通话记录、系统提示等消息,也支持通过自定义渲染器展示业务自定义消息。
消息操作:支持长按菜单操作,例如复制、转发、引用、多选、删除、撤回、语音转文字、翻译、贴表情,以及自定义操作。
高度可定制:支持多种样式配置(例如对齐方式、头像昵称、间距、列表背景、气泡外观),以及消息过滤、自定义消息渲染和自定义操作项。
聊天消息列表 | 消息长按菜单 |
![]() | ![]() |
组件集成
MessageList 是属于 TUIKit Compose 的一个组件,集成 TUIKit Compose 即可获取并使用 MessageList,集成方法请参考文档 TUIKit Compose 里的集成步骤。
组件构成
MessageList 组件对外暴露了消息列表的初始化方法,以及用于在外部控制消息列表的
MessageListController,其他逻辑均封装在 MessageList 中。对外方法
方法名 | 参数 | 描述 |
MessageList | conversationID: String | 初始化组件,设置会话 ID。如果是单聊,组成方式为 c2c_userID。如果是群聊,组成方式为 group_groupID。 |
| modifier: Modifier | Jetpack Compose 中用来设置组件的样式、布局、行为和外观。 |
| config: MessageListConfigProtocol | 初始化组件,设置消息列表的样式、操作项、消息过滤和自定义渲染规则,默认值为 ChatMessageListConfig()。 |
| customActions: List<MessageCustomAction> | 初始化组件,设置自定义消息菜单选项,追加在默认操作项之后。 |
| locateMessage: MessageInfo? | 初始化组件,设置定位消息。通常用于从消息搜索结果页跳转消息页同时定位到目标消息。 |
| messageListViewModelFactory: MessageListViewModelFactory? | 创建组件内部 MessageListViewModel 的工厂类。通常情况下,您无需手动创建,组件已提供默认实现。 |
| controller: MessageListController? | 消息列表控制器,选填。通过 rememberMessageListController() 创建后传入,可在外部退出多选模式、发送“正在输入”状态等,详见下方 MessageListController。 |
| onTypingStatusChanged: (Boolean) -> Unit | 对方“正在输入”状态变化回调,true 表示对方正在输入。仅在单聊且 config 的 enableTyping 为 true 时生效。 |
| onMultiSelectStateChanged: (Boolean) -> Unit | 多选模式状态变化回调,true 表示进入多选模式,false 表示退出多选模式。 |
| onUserClick: (String) -> Unit | 初始化组件,设置点击用户头像跳转响应事件,回调参数为被点击用户的 userID。 |
MessageListController
通过
rememberMessageListController() 创建 MessageListController,并传给 MessageList 的 controller 参数后,可以在外部控制消息列表:方法/属性 | 描述 |
exitMultiSelectMode() | 退出多选模式。 |
isInMultiSelectMode(): Boolean | 当前是否处于多选模式。 |
sendTypingStatus(isTyping: Boolean) | 向对方发送自己的“正在输入”状态,通常与 MessageInput 的 typingStatusSender 配合使用。仅在单聊且 enableTyping 为 true 时生效;为减少无效消息,只有对方在最近 30 秒内给您发过消息时才会发送,并且有频率限制。 |
typingState: StateFlow<Boolean> | 对方是否正在输入,效果与 onTypingStatusChanged 回调相同。 |
基础用法
MessageList 组件可直接初始化使用,需要提供会话 ID。除此之外,我们还建议您在初始化方法中实现
onUserClick。import androidx.compose.foundation.layout.Boximport androidx.compose.foundation.layout.fillMaxSizeimport androidx.compose.foundation.layout.systemBarsPaddingimport androidx.compose.runtime.Composableimport androidx.compose.ui.Modifierimport io.trtc.tuikit.chat.uikit.components.messagelist.ui.MessageList@Composablefun MessageListScreen(conversationID: String, onOpenUserProfile: (userID: String) -> Unit) {Box(modifier = Modifier.fillMaxSize().systemBarsPadding()) {MessageList(conversationID = conversationID) { userID ->// 点击用户头像响应事件onOpenUserProfile(userID)}}}
与 MessageInput 组合使用
MessageList 只负责展示消息,通常与 MessageInput 组合成聊天页面。下面的示例通过
MessageListController 让两个组件协同工作:多选模式下隐藏输入框、按返回键退出多选,以及显示“对方正在输入”提示。import androidx.activity.compose.BackHandlerimport androidx.compose.foundation.layout.Columnimport androidx.compose.foundation.layout.fillMaxSizeimport androidx.compose.foundation.layout.paddingimport androidx.compose.foundation.layout.systemBarsPaddingimport androidx.compose.material3.Textimport androidx.compose.runtime.Composableimport androidx.compose.runtime.getValueimport androidx.compose.runtime.mutableStateOfimport androidx.compose.runtime.rememberimport androidx.compose.runtime.setValueimport androidx.compose.ui.Modifierimport androidx.compose.ui.unit.dpimport io.trtc.tuikit.chat.uikit.components.messageinput.ui.MessageInputimport io.trtc.tuikit.chat.uikit.components.messagelist.ui.MessageListimport io.trtc.tuikit.chat.uikit.components.messagelist.ui.rememberMessageListController@Composablefun ChatScreen(conversationID: String) {val messageListController = rememberMessageListController()var isPeerTyping by remember { mutableStateOf(false) }var isMultiSelectMode by remember { mutableStateOf(false) }// 多选模式下,按返回键退出多选BackHandler(enabled = isMultiSelectMode) {messageListController.exitMultiSelectMode()}Column(modifier = Modifier.fillMaxSize().systemBarsPadding()) {if (isPeerTyping) {Text(text = "对方正在输入...", modifier = Modifier.padding(16.dp))}MessageList(conversationID = conversationID,modifier = Modifier.weight(1f),controller = messageListController,onTypingStatusChanged = { isTyping -> isPeerTyping = isTyping },onMultiSelectStateChanged = { isMultiSelect -> isMultiSelectMode = isMultiSelect },onUserClick = { userID ->// 点击用户头像响应事件})// 多选模式下隐藏输入框if (!isMultiSelectMode) {MessageInput(conversationID = conversationID,typingStatusSender = { isTyping ->// 把自己的输入状态发送给对方messageListController.sendTypingStatus(isTyping)})}}}
说明:
示例工程(demo)中提供了基于 ChatPage 封装好的聊天页 ChatActivity(带标题栏、未读角标、群事件处理等),可直接复用或参考其实现进行自定义:ChatActivity.start(context, conversationID)。
自定义组件
您可以自定义消息列表的样式、操作项、需要展示的消息以及自定义消息的渲染方式。方法如下。
自定义样式
推荐使用
ChatMessageListConfig 设置样式。ChatMessageListConfig 的构造参数均为可选的命名参数,未设置的属性使用默认值:import androidx.compose.ui.unit.dpimport io.trtc.tuikit.chat.uikit.components.config.MessageAlignmentimport io.trtc.tuikit.chat.uikit.components.messagelist.config.ChatMessageListConfigimport io.trtc.tuikit.chat.uikit.components.messagelist.ui.MessageListval messageListConfig = ChatMessageListConfig(alignment = MessageAlignment.TWO_SIDED, // 自己发送的消息在右侧,其他人的消息在左侧isShowRightAvatar = false, // 不显示右侧(自己发送的消息)的头像isShowTimeMessage = false, // 不显示时间分隔cellSpacing = 16.dp, // 消息之间的间距horizontalPadding = 12.dp // 消息列表的左右边距)MessageList(conversationID = conversationID, config = messageListConfig) { userID ->// 点击用户头像响应事件}
ChatMessageListConfig 中与样式相关的属性说明如下,操作项相关的开关请参见“自定义操作项”:属性名 | 类型 | 描述 | 备注 |
alignment | MessageAlignment | 消息对齐方式 | MessageAlignment.LEFT:所有消息左对齐。MessageAlignment.RIGHT:所有消息右对齐。MessageAlignment.TWO_SIDED:自己发送的消息右对齐,其他人的消息左对齐。默认值为 TWO_SIDED。 |
isShowTimeMessage | Boolean | 是否显示时间消息 | 控制是否在消息之间显示时间分隔。默认值为 true。 |
isShowLeftAvatar | Boolean | 是否显示左侧头像 | 控制显示在左侧的消息是否显示头像,TWO_SIDED 对齐时即其他人发送的消息。默认值为 true。 |
isShowLeftNickname | Boolean | 是否显示左侧昵称 | 控制显示在左侧的消息是否显示昵称。默认值为 true。 |
isShowRightAvatar | Boolean | 是否显示右侧头像 | 控制显示在右侧的消息是否显示头像,TWO_SIDED 对齐时即自己发送的消息。默认值为 true。 |
isShowRightNickname | Boolean | 是否显示右侧昵称 | 控制显示在右侧的消息是否显示昵称。默认值为 true。 |
cellSpacing | Dp | 消息间距 | 控制相邻消息之间的间距。默认值为 10.dp。 |
isShowSystemMessage | Boolean | 是否显示系统消息 | 控制是否显示群提示消息和撤回提示。默认值为 true。 |
isShowUnsupportMessage | Boolean | 是否显示不支持的消息 | 控制是否显示组件无法识别、只能以默认样式展示的消息。默认值为 true。 |
horizontalPadding | Dp | 水平内边距 | 控制消息列表的左右内边距。默认值为 16.dp。 |
avatarSpacing | Dp | 头像间距 | 控制头像与消息内容之间的间距。默认值为 8.dp。 |
isShowReadReceipt | Boolean | 是否显示已读回执 | 控制自己发送的、需要已读回执的消息是否显示已读状态。消息需要由开启了 enableReadReceipt 的 MessageInput 发送。默认值为 false。 |
enableTyping | Boolean | 是否启用“正在输入”功能 | 仅单聊生效,需要配合 MessageListController 使用。默认值为 true。 |
background | MessageListBackground? | 消息列表背景 | 默认值为 null,详见下方“列表背景”。 |
defaultBubbleAppearance、leftBubbleAppearance、rightBubbleAppearance、ownBubbleAppearance、incomingBubbleAppearance | MessageBubbleAppearance? | 消息气泡外观 | 默认值均为 null,详见下方“气泡外观”。 |
昵称的显示还受会话类型和对齐方式影响:其他人发送的消息仅在群聊中显示昵称,自己发送的消息仅在 alignment 不为 TWO_SIDED 时显示昵称。
列表背景
通过
setBackgroundColor、setBackgroundGradient、setBackgroundImage 设置消息列表的背景,clearBackground 可清除设置:import io.trtc.tuikit.chat.uikit.components.messagelist.config.ChatMessageListConfigimport io.trtc.tuikit.chat.uikit.components.messagelist.config.MessageListBackground// 纯色背景val colorBackgroundConfig = ChatMessageListConfig().setBackgroundColor(0xFFF5F6F8.toInt())// 渐变背景,至少需要 2 个颜色val gradientBackgroundConfig = ChatMessageListConfig().setBackgroundGradient(colors = intArrayOf(0xFFE8F0FE.toInt(), 0xFFFFFFFF.toInt()),direction = MessageListBackground.GradientDirection.TOP_BOTTOM)// 图片背景val imageBackgroundConfig = ChatMessageListConfig().setBackgroundImage("https://example.com/chat_background.png")
setBackgroundImage 的参数会交给 Coil 加载,支持网络图片 URL、本地文件、Uri、drawable 资源 ID 等。渐变方向 GradientDirection 支持 TOP_BOTTOM、BOTTOM_TOP、LEFT_RIGHT、RIGHT_LEFT、TOP_LEFT_BOTTOM_RIGHT、BOTTOM_RIGHT_TOP_LEFT,默认为 TOP_BOTTOM。
背景的生效优先级为:config 中设置的背景 > 用户在聊天设置中为该会话选择的聊天背景 > 默认背景色。
气泡外观
通过
setDefaultBubbleAppearance、setLeftBubbleAppearance、setRightBubbleAppearance、setOwnBubbleAppearance、setIncomingBubbleAppearance 设置消息气泡的外观,对应的 clearXxxBubbleAppearance 方法可清除设置。多个外观按“默认 → 左侧/右侧 → 自己/他人”的顺序逐个字段合并,后者中设置了的字段会覆盖前者,圆角按每个角单独合并:import io.trtc.tuikit.chat.uikit.components.messagelist.config.ChatMessageListConfigimport io.trtc.tuikit.chat.uikit.components.messagelist.config.MessageBubbleAppearanceimport io.trtc.tuikit.chat.uikit.components.messagelist.config.MessageBubbleBackgroundimport io.trtc.tuikit.chat.uikit.components.messagelist.config.MessageBubbleCornerRadiusimport io.trtc.tuikit.chat.uikit.components.messagelist.config.MessageBubbleStrokeval bubbleConfig = ChatMessageListConfig()// 所有气泡的基础外观:四个角的圆角均为 12dp.setDefaultBubbleAppearance(MessageBubbleAppearance(cornerRadius = MessageBubbleCornerRadius.all(12)))// 自己发送的消息:渐变背景,右下角为直角,其余圆角沿用基础外观.setOwnBubbleAppearance(MessageBubbleAppearance(background = MessageBubbleBackground.Gradient(colors = listOf(0xFF4F8BFF.toInt(), 0xFF1C66E5.toInt()),direction = MessageBubbleBackground.GradientDirection.LEFT_RIGHT),cornerRadius = MessageBubbleCornerRadius(bottomRight = 0)))// 收到的消息:白色背景,1dp 描边.setIncomingBubbleAppearance(MessageBubbleAppearance(background = MessageBubbleBackground.Color(0xFFFFFFFF.toInt()),stroke = MessageBubbleStroke(width = 1, color = 0xFFE5E6EB.toInt())))
MessageBubbleAppearance 的字段说明如下,尺寸参数的单位均为 dp,颜色参数为 ARGB 格式的 Int 值:字段 | 类型 | 描述 |
background | MessageBubbleBackground? | 气泡背景,支持 Color(纯色)、Gradient(渐变,至少 2 个颜色)、DrawableResource(drawable 资源 ID)、DrawableValue(Drawable 对象)。 |
cornerRadius | MessageBubbleCornerRadius? | 四个角的圆角半径(topLeft、topRight、bottomRight、bottomLeft),可以通过 MessageBubbleCornerRadius.all(radius) 统一设置。 |
stroke | MessageBubbleStroke? | 描边的宽度和颜色。 |
contentInsets | MessageBubbleInsets? | 气泡与消息内容之间的内边距,在消息内容自身边距的基础上额外增加。可以通过 MessageBubbleInsets.all(value)、MessageBubbleInsets.symmetric(horizontal, vertical) 快速创建。 |
minimumSize | MessageBubbleSize? | 气泡的最小宽度和最小高度。 |
气泡外观仅作用于使用默认气泡的消息,例如文本、语音、文件、通话记录消息,以及
renderConfig.useDefaultBubble 为 true 的自定义渲染器。图片、视频、表情消息默认不带气泡,仅在带有表情回应时包裹一层默认气泡。自定义操作项
您可以采用多种方式自定义长按消息菜单项。默认操作项依次为:复制、转发、引用、多选、删除、撤回、转文字、翻译、从当前听,菜单末尾还有“贴表情”入口。每个操作项只在适用的消息上展示,具体条件见方式 1 中的表格。
方式 1. 隐藏/显示操作项
初始化 MessageList 时,通过设置 config 中的
isSupportXxx 开关控制操作项是否显示:import io.trtc.tuikit.chat.uikit.components.messagelist.config.ChatMessageListConfigimport io.trtc.tuikit.chat.uikit.components.messagelist.ui.MessageListMessageList(conversationID = conversationID,config = ChatMessageListConfig(isSupportCopy = false) // 不展示“复制”) { userID ->// 点击用户头像响应事件}
目前支持的操作项开关
开关 | 对应操作项 ID | 描述 |
isSupportCopy | MessageActionIDs.COPY | 复制,仅文本消息展示。默认值取决于全局配置。 |
isSupportForward | MessageActionIDs.FORWARD | 转发,仅发送成功的消息展示。默认值为 true。 |
isSupportQuote | MessageActionIDs.QUOTE | 引用,仅发送成功的消息展示。默认值取决于全局配置。 |
isSupportMultiSelect | MessageActionIDs.MULTI_SELECT | 多选,点击后进入多选模式。默认值为 true。 |
isSupportDelete | MessageActionIDs.DELETE | 删除,点击后会先弹出确认框。默认值取决于全局配置。 |
isSupportRecall | MessageActionIDs.RECALL | 撤回,仅自己发送成功、且发送时间在 2 分钟以内的消息展示。默认值取决于全局配置。 |
isSupportConvertToText | MessageActionIDs.CONVERT_TO_TEXT | 转文字,仅发送成功、且当前未显示转写结果的语音消息展示。默认值为 true。 |
isSupportTranslate | MessageActionIDs.TRANSLATE | 翻译,仅发送成功、且当前未显示译文的文本消息展示。默认值为 true。 |
isSupportListenFromHere | MessageActionIDs.LISTEN_FROM_HERE | 从当前听,从该消息开始依次朗读或播放到最新一条消息。默认值为 true。 |
isSupportReaction | 无 | 表情回应。开启后,发送成功的消息的长按菜单末尾会展示“贴表情”入口,消息下方会展示表情回应。该入口不属于可编辑的操作项。默认值为 true。 |
方式 2. 增加操作项
初始化 MessageList 时传入
customActions,MessageList 内部会在默认操作项之后(“贴表情”入口之前)添加您增加的自定义选项:import io.trtc.tuikit.chat.uikit.components.messagelist.model.MessageCustomActionimport io.trtc.tuikit.chat.uikit.components.messagelist.ui.MessageListMessageList(conversationID = conversationID,customActions = listOf(MessageCustomAction(ID = "custom.message.share",title = "Share",iconResID = android.R.drawable.ic_menu_share,action = { message ->println("Share Message: ${message.msgID}")})))
MessageCustomAction 的字段说明如下。由于 action 不是最后一个参数,请以 action = { } 命名参数的方式传入:字段 | 类型 | 描述 |
ID | String | 操作项的唯一标识,必填。 |
title | String | 操作项标题。 |
iconResID | Int | 操作项图标的 drawable 资源 ID,为 0 时不显示图标。图标会按主题的文字颜色着色。 |
action | (MessageInfo) -> Unit | 点击操作项时的回调,参数为当前长按的消息。 |
dangerous | Boolean | 是否为危险操作,默认为 false。目前不影响长按菜单的显示样式。 |
方式 3. 局部编辑操作菜单
如需调整操作项的顺序、修改默认操作项,或者根据消息动态增删操作项,可以通过
ChatMessageListConfig 的 customizeActions 编辑长按菜单。每次长按消息时,组件会先根据开关和消息状态生成默认操作项,再执行 customizeActions 中的代码,然后追加 customActions 中的操作项,最后根据 isSupportReaction 追加“贴表情”入口。在 customizeActions 中,可以通过
editorContext.message 获取当前长按的消息,通过 editorContext.conversationID 获取会话 ID,通过 editorContext.androidContext 获取 Android Context,并调用以下方法编辑操作项:方法 | 描述 |
add(item) | 在末尾添加操作项。item 的 ID 为空白或与已有操作项重复时会抛出 IllegalArgumentException。 |
remove(ID) | 移除指定 ID 的操作项,不存在时返回 false。 |
replace(ID) { item -> ... } | 替换指定 ID 的操作项,不存在时返回 false。替换后的操作项必须保持 ID 不变,否则会抛出异常。 |
insertBefore(anchorID, item) / insertAfter(anchorID, item) | 在锚点操作项之前或之后插入操作项。锚点不存在时返回 false,且不会插入。item 的 ID 规则与 add 相同。 |
moveBefore(ID, anchorID) / moveAfter(ID, anchorID) | 将操作项移动到锚点操作项之前或之后,任意一个 ID 不存在时返回 false。 |
clear() | 移除全部操作项。 |
items | 当前操作项列表的只读快照。 |
示例代码如下:
import io.trtc.tuikit.atomicxcore.api.message.MessageTypeimport io.trtc.tuikit.chat.uikit.components.messagelist.config.ChatMessageListConfigimport io.trtc.tuikit.chat.uikit.components.messagelist.model.MessageActionIDsimport io.trtc.tuikit.chat.uikit.components.messagelist.model.MessageCustomActionval editActionsConfig = ChatMessageListConfig().customizeActions {// 当前长按的消息val message = editorContext.message// 移除“多选”remove(MessageActionIDs.MULTI_SELECT)// 修改“删除”的标题。ID 保持不变,点击后仍会先弹出确认框replace(MessageActionIDs.DELETE) { action ->action.copy(title = "删除消息")}// 文本消息增加“收藏”if (message.messageType == MessageType.TEXT) {val favoriteAction = MessageCustomAction(ID = "custom.message.favorite",title = "收藏",iconResID = android.R.drawable.star_off,action = { target ->// 收藏消息 target})// 放在“转发”之后;当前消息没有“转发”(例如发送失败)时,追加到末尾if (!insertAfter(MessageActionIDs.FORWARD, favoriteAction)) {add(favoriteAction)}}}MessageList(conversationID = conversationID, config = editActionsConfig)
自定义效果如下图所示:
消息列表操作(默认选项) | 消息列表操作(隐藏复制选项) | 消息列表操作(新增分享选项) |
![]() | ![]() | ![]() |





