实现缩放动画菜单和 Scrim 关闭

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
xfy 2026-05-18 11:46:43 +08:00
parent 2b0bb7e1d8
commit ff3bd6629d

View File

@ -1,5 +1,14 @@
package plus.rua.project.ui package plus.rua.project.ui
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
@ -7,6 +16,10 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.layout.statusBarsPadding
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.HorizontalPager
import androidx.compose.foundation.pager.PagerDefaults import androidx.compose.foundation.pager.PagerDefaults
import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.foundation.pager.rememberPagerState
@ -15,6 +28,7 @@ import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
@ -22,8 +36,10 @@ import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.TransformOrigin import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -65,6 +81,12 @@ fun CalendarMonthView(
var screenWidthPx by remember { mutableIntStateOf(0) } var screenWidthPx by remember { mutableIntStateOf(0) }
var screenHeightPx by remember { mutableIntStateOf(0) } var screenHeightPx by remember { mutableIntStateOf(0) }
var calendarContentHeightPx by remember { mutableIntStateOf(0) } var calendarContentHeightPx by remember { mutableIntStateOf(0) }
var isMenuExpanded by remember { mutableStateOf(false) }
// 视图切换时自动关闭菜单
LaunchedEffect(viewModel.isYearView) {
isMenuExpanded = false
}
val pagerState = rememberPagerState(initialPage = START_PAGE, pageCount = { Int.MAX_VALUE }) val pagerState = rememberPagerState(initialPage = START_PAGE, pageCount = { Int.MAX_VALUE })
@ -344,5 +366,86 @@ fun CalendarMonthView(
) )
} }
} }
// Scrim菜单展开时覆盖全屏点击关闭
if (isMenuExpanded) {
Box(
modifier = Modifier
.fillMaxSize()
.pointerInput(Unit) {
detectTapGestures { isMenuExpanded = false }
}
.background(Color.Black.copy(alpha = 0.32f))
)
}
// 缩放动画菜单
AnimatedVisibility(
visible = isMenuExpanded,
enter = scaleIn(
initialScale = 0.6f,
animationSpec = tween(150),
transformOrigin = TransformOrigin(0f, 1f)
) + fadeIn(tween(150)),
exit = scaleOut(
targetScale = 0.6f,
animationSpec = tween(100),
transformOrigin = TransformOrigin(0f, 1f)
) + fadeOut(tween(100)),
modifier = Modifier
.align(Alignment.BottomStart)
.padding(start = 16.dp, bottom = with(density) { cardHeightPx.toDp() } + 72.dp)
) {
Column(
modifier = Modifier
.background(
MaterialTheme.colorScheme.surfaceContainerHigh,
RoundedCornerShape(12.dp)
)
.width(140.dp)
) {
MenuItem(
text = "月视图",
selected = !viewModel.isYearView,
onClick = {
isMenuExpanded = false
if (viewModel.isYearView) viewModel.toggleYearView()
}
)
MenuItem(
text = "年视图",
selected = viewModel.isYearView,
onClick = {
isMenuExpanded = false
if (!viewModel.isYearView) viewModel.toggleYearView()
}
)
}
}
}
}
@Composable
private fun MenuItem(
text: String,
selected: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier
) {
Box(
modifier = modifier
.fillMaxWidth()
.clickable(onClick = onClick)
.background(
if (selected) MaterialTheme.colorScheme.primaryContainer else Color.Transparent
)
.padding(horizontal = 16.dp, vertical = 12.dp)
) {
Text(
text = text,
color = if (selected) MaterialTheme.colorScheme.onPrimaryContainer
else MaterialTheme.colorScheme.onSurface,
style = MaterialTheme.typography.bodyLarge
)
} }
} }