优化(UI): 修复 Compose 的悬浮窗灾难性重组

利用延迟读取(Deferred State Reading)的特性,将 fabOffsetX 等坐标变量的读取放置在 Modifier.offset 的 lambda 内部。
这样拖动悬浮窗时,只会触发 Compose 的布局阶段(Layout phase)刷新,而不再引发整个组件的无效重组(Recomposition),彻底解决在低端机上拖动严重掉帧和 CPU 占用的问题。
This commit is contained in:
fengge 2026-06-03 14:48:56 +08:00
parent 96068d56b2
commit 89f1df9a9b
1 changed files with 7 additions and 13 deletions

View File

@ -94,25 +94,19 @@ fun FloatingChatWidget() {
visible = true
}
// 👈 用 FAB 位置计算对话框位置,但强制钳制在屏幕内
// FAB右下角为基准对话框应该出现在 FAB 附近
val fabRight = screenWidthPx - paddingPx * 2 + fabOffsetX // FAB右边缘
val fabBottom = screenHeightPx - paddingPx * 2 - navBarPx + fabOffsetY // FAB下边缘
// 对话框优先放在 FAB 左上方,如果放不下就贴边
val rawX = fabRight - cardWidthPx - paddingPx // FAB左边
val rawY = fabBottom - cardHeightPx - paddingPx // FAB上边
// 👈 关键:钳制到屏幕内
val clampedX = rawX.coerceIn(0f, screenWidthPx - cardWidthPx)
val clampedY = rawY.coerceIn(0f, screenHeightPx - cardHeightPx)
AnimatedVisibility(
visible = visible,
enter = fadeIn(animationSpec = tween(300)) + scaleIn(initialScale = 0.8f, animationSpec = tween(300)),
exit = fadeOut(animationSpec = tween(200)) + scaleOut(targetScale = 0.8f, animationSpec = tween(200)),
modifier = Modifier
.offset {
val fabRight = screenWidthPx - paddingPx * 2 + fabOffsetX
val fabBottom = screenHeightPx - paddingPx * 2 - navBarPx + fabOffsetY
val rawX = fabRight - cardWidthPx - paddingPx
val rawY = fabBottom - cardHeightPx - paddingPx
val clampedX = rawX.coerceIn(0f, screenWidthPx - cardWidthPx)
val clampedY = rawY.coerceIn(0f, screenHeightPx - cardHeightPx)
IntOffset(
(clampedX + cardDragX).roundToInt()
.coerceIn(0, (screenWidthPx - cardWidthPx).toInt()),