重做语言选择浮层布局

This commit is contained in:
BoatingCloud committed 2026-08-27 15:45:23 +08:00
1 parent d159ec4a99
commit 5d41a0b95f
3 files changed
+41 -10

No files matched your search

@@ -49,6 +49,7 @@ import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.layout.boundsInRoot
import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.positionInRoot
import androidx.compose.ui.input.pointer.pointerInput
@@ -127,7 +128,7 @@ fun SettingsScreen(
icon = Icons.Outlined.Language,
title = "语言",
subtitle = AppLanguage.displayName,
modifier = Modifier.onGloballyPositioned { languageEntryBounds = it.boundsInRoot() },
onTrailingIconPositioned = { languageEntryBounds = it.boundsInRoot() },
onClick = {
languageMenuMounted = true
showLanguageDialog = true
@@ -200,6 +201,7 @@ private fun SettingRowItem(
title: String,
subtitle: String,
modifier: Modifier = Modifier,
onTrailingIconPositioned: ((LayoutCoordinates) -> Unit)? = null,
onClick: () -> Unit,
) {
Row(
@@ -225,13 +227,26 @@ private fun SettingRowItem(
Text(subtitle, color = Color(0xFF6B7280), fontSize = 12.sp)
}
}
Icon(Icons.Outlined.ChevronRight, null, tint = Color.LightGray, modifier = Modifier.size(20.dp))
Icon(
Icons.Outlined.ChevronRight,
null,
tint = Color.LightGray,
modifier = Modifier
.size(20.dp)
.then(
if (onTrailingIconPositioned != null) {
Modifier.onGloballyPositioned(onTrailingIconPositioned)
} else {
Modifier
},
),
)
}
}
@Composable
private fun DividerLine() {
Box(Modifier.fillMaxWidth().height(0.5.dp).background(Color(0xFFE5E7EB)))
Box(Modifier.fillMaxWidth().height(0.5.dp).padding(horizontal = 16.dp).background(Color(0xFFE5E7EB)))
}
@Composable
@@ -268,13 +283,20 @@ private fun LanguageMenuOverlay(
val widthProgress = 1f - (1f - rawProgress) * (1f - rawProgress) * (1f - rawProgress)
val heightProgress = 1f - (1f - rawProgress) * (1f - rawProgress)
val contentProgress = ((rawProgress - 0.38f) / 0.62f).coerceIn(0f, 1f)
val menuWidth = 46.dp + (220.dp - 46.dp) * widthProgress
val menuHeight = 46.dp + (128.dp - 46.dp) * heightProgress
val initialSize = 44.dp
val finalWidth = 184.dp
val finalHeight = 112.dp
val menuWidth = initialSize + (finalWidth - initialSize) * widthProgress
val menuHeight = initialSize + (finalHeight - initialSize) * heightProgress
val cornerRadius = 23.dp + (28.dp - 23.dp) * rawProgress
val menuWidthPx = with(density) { menuWidth.roundToPx() }
val menuHeightPx = with(density) { menuHeight.roundToPx() }
val menuLeft = (anchorBounds.right - rootOrigin.x - menuWidthPx).roundToInt()
val menuTop = (anchorBounds.top - rootOrigin.y).roundToInt()
val initialHalfPx = with(density) { initialSize.toPx() / 2f }
val anchorCenterX = anchorBounds.center.x - rootOrigin.x
val anchorCenterY = anchorBounds.center.y - rootOrigin.y
val menuRight = anchorCenterX + initialHalfPx
val menuLeft = (menuRight - menuWidthPx).roundToInt()
val menuTop = (anchorCenterY - initialHalfPx).roundToInt()
val menuRect = Rect(
menuLeft.toFloat(),
menuTop.toFloat(),
@@ -283,7 +305,11 @@ private fun LanguageMenuOverlay(
)
val currentMenuRect by rememberUpdatedState(menuRect)
val shape = RoundedCornerShape(cornerRadius)
val surface = if (GlassTokens.isDark) Color.White.copy(alpha = 0.10f) else Color.White.copy(alpha = 0.42f)
val surface = if (GlassTokens.isDark) {
Color.White.copy(alpha = 0.08f)
} else {
Color.Black.copy(alpha = 0.10f)
}
val border = if (GlassTokens.isDark) Color.White.copy(alpha = 0.24f) else Color.White.copy(alpha = 0.62f)
Box(
@@ -291,8 +317,6 @@ private fun LanguageMenuOverlay(
.fillMaxSize()
.zIndex(10f),
) {
// Keep the outside gesture layer below the menu itself. The opening
// gesture cannot be reused to dismiss the newly mounted overlay.
Box(
Modifier
.fillMaxSize()
+6
View File
@@ -4,3 +4,9 @@
文件变更: app/build.gradle.kts、MainApp.kt、screens/SettingsScreen.kt、ui/AppBottomBar.kt、ui/liquidglass/LiquidBottomTabs.kt,以及此前待推送的播放器、首页、搜索、收藏和数据文件。
教训: 参考仓库没有现成菜单组件,需复用其 drawBackdrop 组件模式;来源层与玻璃消费层必须分离,外部手势层需放在菜单内容下方。
标签: #lumaplayer #android-liquid-glass #backdrop #language-menu #bottom-bar
[PROJECT:lumaplayer] 重做语言菜单浮层几何
结论: 删除语言菜单与列表视觉耦合,保留原语言切换逻辑,使用右侧 Chevron 实际坐标作为锚点,独立 Overlay 从 44dp 玻璃圆向左下 Morph 为紧凑菜单。
文件变更: screens/SettingsScreen.kt。
教训: Overlay 即使不参与测量,若最终几何直接贴在整行顶部也会产生“Row 横向展开”的视觉错觉;应锚定入口图标并固定展开方向与尺寸。
标签: #lumaplayer #language-menu #overlay #morph #backdrop
+1
View File
@@ -13,3 +13,4 @@
- 2026-08-27:同步远端 `fc35ae9`;合并服务器选择持久化和资源库点击后回首页逻辑,保留本地详情/播放器全屏与透明底栏修复;Debug 构建通过。
- 2026-08-27:语言菜单改为真实锚点的 Backdrop 液态玻璃 Morph Overlay;底栏主体和搜索圆钮复用 AndroidLiquidGlass-kmp 的 `drawBackdrop`、`vibrancy`、`blur`、`lens`、高光和阴影实现;展开 180ms、关闭 300ms,外部点击和语言选择验证通过。
- 当前依赖:`io.github.kyant0:backdrop:2.0.1`、`io.github.kyant0:shapes:1.2.1`;未纳入本地参考素材和压缩包。
- 2026-08-27:重做语言菜单 Overlay 几何,改用右侧 Chevron 的 `onGloballyPositioned` 作为锚点,44dp 圆形向左下 Morph 为 184×112dp 独立玻璃容器;LanguageRow/PlaybackRow bounds 保持不变。