From 0cf1d295a4c96410a0d1585118a942f78772a556 Mon Sep 17 00:00:00 2001 From: yangshilin <2157598560@qq.com> Date: Wed, 11 Mar 2026 17:08:42 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E8=BF=9B=E5=85=A5=E5=AF=B9=E8=AF=9D?= =?UTF-8?q?=E4=B9=8B=E5=90=8E=E9=BB=98=E8=AE=A4=E5=B1=95=E7=A4=BA=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E6=B6=88=E6=81=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ui/components/chat/MessageList.kt | 34 +++++++++++-------- .../ui/screens/CreateMemoryScreen.kt | 1 + 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/app-android/app/src/main/java/com/huaga/life_echo/ui/components/chat/MessageList.kt b/app-android/app/src/main/java/com/huaga/life_echo/ui/components/chat/MessageList.kt index 17c68b7..1bf7381 100644 --- a/app-android/app/src/main/java/com/huaga/life_echo/ui/components/chat/MessageList.kt +++ b/app-android/app/src/main/java/com/huaga/life_echo/ui/components/chat/MessageList.kt @@ -12,6 +12,8 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue +import androidx.compose.runtime.key +import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope @@ -34,8 +36,9 @@ import kotlinx.coroutines.launch /** * 消息列表组件 - * + * * @param messages 消息列表 + * @param conversationId 当前对话 ID,用于切换对话时重置滚动状态,使每次打开都从底部开始 * @param isStreaming 是否正在流式接收 * @param streamingText 流式文本内容 * @param isTyping 是否正在输入 @@ -46,6 +49,7 @@ import kotlinx.coroutines.launch @Composable fun MessageList( messages: List, + conversationId: String? = null, isStreaming: Boolean = false, streamingText: String = "", isTyping: Boolean = false, @@ -57,46 +61,48 @@ fun MessageList( audioFilePaths: Map = emptyMap(), audioDurations: Map = emptyMap() // messageId -> 时长(秒) ) { - val listState = rememberLazyListState() val scope = rememberCoroutineScope() var lastHeightPx by remember { mutableIntStateOf(0) } - // 计算实际的列表项数量(考虑分割消息和附加项) + // 计算实际的列表项数量(考虑分割消息和附加项)- 需在 listState 之前计算,用于初始滚动位置 val estimatedItemCount = remember(messages, isStreaming, streamingText, isTyping) { var count = 0 var lastTimestamp: Long? = null - + messages.forEachIndexed { index, message -> - // 时间分隔线 if (index > 0 && lastTimestamp != null && (message.timestamp - lastTimestamp!!) > 300000) { count++ } - - // 消息气泡(考虑分割) if (message.senderType == "assistant") { val parts = message.content.split("[SPLIT]").filter { it.trim().isNotEmpty() } count += if (parts.size > 1) parts.size else 1 } else { count++ } - lastTimestamp = message.timestamp } - - // 流式消息 if (isStreaming) { val streamingParts = streamingText.split("[SPLIT]").filter { it.trim().isNotEmpty() } count += if (streamingParts.size > 1) streamingParts.size else 1 } - - // 输入指示器 if (isTyping || (isStreaming && streamingText.isEmpty())) { count++ } - count } - + + // 当前对话是否已加载过消息(用于首次显示时直接定位到底部,避免从顶部再滑到底部) + var hasReceivedMessages by remember(conversationId) { mutableStateOf(false) } + LaunchedEffect(conversationId, messages) { + if (messages.isNotEmpty()) hasReceivedMessages = true + } + + // 用 key 在「首次有消息」时重建列表状态,使 initialFirstVisibleItemIndex 生效,打开对话即显示底部 + val initialIndex = if (hasReceivedMessages && estimatedItemCount > 0) (estimatedItemCount - 1).coerceAtLeast(0) else 0 + val listState = key(conversationId, hasReceivedMessages) { + rememberLazyListState(initialFirstVisibleItemIndex = initialIndex, initialFirstVisibleItemScrollOffset = 0) + } + // 自动滚动到底部 - 当消息变化或流式内容更新时滚动 LaunchedEffect(messages.size, messages.lastOrNull()?.id, isStreaming, streamingText, isTyping) { // 短暂延迟确保内容已渲染 diff --git a/app-android/app/src/main/java/com/huaga/life_echo/ui/screens/CreateMemoryScreen.kt b/app-android/app/src/main/java/com/huaga/life_echo/ui/screens/CreateMemoryScreen.kt index 489df4a..de2ea58 100644 --- a/app-android/app/src/main/java/com/huaga/life_echo/ui/screens/CreateMemoryScreen.kt +++ b/app-android/app/src/main/java/com/huaga/life_echo/ui/screens/CreateMemoryScreen.kt @@ -189,6 +189,7 @@ fun CreateMemoryScreen( // 使用新的MessageList组件(包含所有消息、流式内容和输入指示器) MessageList( messages = messages, + conversationId = conversationId, isStreaming = isStreaming, streamingText = streamingText, isTyping = isTyping,