重做语言选择浮层布局
This commit is contained in:
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()
|
||||
|
||||
@@ -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
|
||||
@@ -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 保持不变。
|
||||
Reference in new issue
Block a user