feat: 移除共享元素转场,月/年视图切换改用缩放+淡入淡出动画

This commit is contained in:
xfy 2026-06-01 11:11:45 +08:00
parent 1930bbcb7f
commit 4a8480be64
2 changed files with 37 additions and 76 deletions

View File

@ -4,7 +4,6 @@ import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.EnterTransition import androidx.compose.animation.EnterTransition
import androidx.compose.animation.ExitTransition import androidx.compose.animation.ExitTransition
import androidx.compose.animation.SharedTransitionLayout
import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.Spring import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.animateFloatAsState
@ -12,11 +11,8 @@ import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut import androidx.compose.animation.fadeOut
import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.animation.scaleIn import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut import androidx.compose.animation.scaleOut
import androidx.compose.animation.slideInVertically
import androidx.compose.animation.slideOutVertically
import androidx.compose.animation.togetherWith import androidx.compose.animation.togetherWith
import androidx.compose.ui.graphics.TransformOrigin import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.graphicsLayer
@ -88,14 +84,13 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import plus.rua.project.util.logd import plus.rua.project.util.logd
/** /**
* 日历主界面包含月/周视图切换折叠动画和年视图共享元素转场 * 日历主界面包含月/周视图切换折叠动画和年视图转场
* *
* 折叠时日历从月视图收缩为周视图1BottomCard 同步上移填充空间 * 折叠时日历从月视图收缩为周视图1BottomCard 同步上移填充空间
* 通过左下角 FAB 菜单切换月/年视图使用 SharedTransitionLayout 实现共享元素转场 * 通过左下角 FAB 菜单切换月/年视图
* *
* @param modifier 外部布局修饰符 * @param modifier 外部布局修饰符
*/ */
@OptIn(ExperimentalSharedTransitionApi::class)
@Composable @Composable
fun CalendarMonthView( fun CalendarMonthView(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@ -185,8 +180,6 @@ fun CalendarMonthView(
screenWidthPx = size.width screenWidthPx = size.width
} }
) { ) {
SharedTransitionLayout {
val sharedScope = this
var lastLoggedTargetState by remember { mutableStateOf(false) } var lastLoggedTargetState by remember { mutableStateOf(false) }
SideEffect { SideEffect {
if (lastLoggedTargetState != isYearView) { if (lastLoggedTargetState != isYearView) {
@ -198,10 +191,14 @@ fun CalendarMonthView(
targetState = isYearView, targetState = isYearView,
label = "month_year_transition", label = "month_year_transition",
transitionSpec = { transitionSpec = {
val enter = fadeIn(tween(300, easing = FastOutSlowInEasing)) + val enter = scaleIn(
slideInVertically(tween(300, easing = FastOutSlowInEasing)) { it / 6 } initialScale = 0.85f,
val exit = fadeOut(tween(200, easing = FastOutSlowInEasing)) + animationSpec = tween(350, easing = FastOutSlowInEasing)
slideOutVertically(tween(200, easing = FastOutSlowInEasing)) { -it / 6 } ) + fadeIn(tween(250, easing = FastOutSlowInEasing))
val exit = scaleOut(
targetScale = 0.85f,
animationSpec = tween(250, easing = FastOutSlowInEasing)
) + fadeOut(tween(200, easing = FastOutSlowInEasing))
enter togetherWith exit enter togetherWith exit
}, },
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
@ -261,9 +258,6 @@ fun CalendarMonthView(
val onRowHeightMeasured = remember { val onRowHeightMeasured = remember {
{ h: Int -> if (h > 0) rowHeightPx = h } { h: Int -> if (h > 0) rowHeightPx = h }
} }
with(sharedScope) {
// P0: 缓存 sharedElement tween避免每次重组创建新实例导致动画重新计算
val sharedTween = remember { tween<androidx.compose.ui.geometry.Rect>(400, easing = FastOutSlowInEasing) }
CalendarPagerArea( CalendarPagerArea(
selectedDate = selectedDate, selectedDate = selectedDate,
today = today, today = today,
@ -276,17 +270,8 @@ fun CalendarMonthView(
shiftKindAt = shiftKindAt, shiftKindAt = shiftKindAt,
onRowHeightMeasured = onRowHeightMeasured, onRowHeightMeasured = onRowHeightMeasured,
pagerState = pagerState, pagerState = pagerState,
modifier = Modifier modifier = Modifier.clipToBounds()
.sharedElement(
sharedContentState = rememberSharedContentState(
key = "month_grid_${currentYear}_${currentMonth}"
),
animatedVisibilityScope = this@AnimatedContent,
boundsTransform = { _, _ -> sharedTween }
) )
.clipToBounds()
)
}
BottomCardArea( BottomCardArea(
viewModel = viewModel, viewModel = viewModel,
today = today, today = today,
@ -365,8 +350,6 @@ fun CalendarMonthView(
coroutineScope.launch { pagerState.scrollToPage(targetPage) } coroutineScope.launch { pagerState.scrollToPage(targetPage) }
} }
}, },
sharedTransitionScope = sharedScope,
animatedVisibilityScope = this@AnimatedContent,
modifier = Modifier modifier = Modifier
) )
} }
@ -374,7 +357,6 @@ fun CalendarMonthView(
composeTraceEndSection() composeTraceEndSection()
} }
} }
}
// FAB 浮动按钮 // FAB 浮动按钮
FloatingActionButton( FloatingActionButton(

View File

@ -1,9 +1,6 @@
package plus.rua.project.ui package plus.rua.project.ui
import androidx.compose.animation.AnimatedContent import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibilityScope
import androidx.compose.animation.ExperimentalSharedTransitionApi
import androidx.compose.animation.SharedTransitionScope
import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.animateFloatAsState import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
@ -74,19 +71,14 @@ private data class MiniMonthColors(
* @param selectedMonth 当前选中月份1-12 * @param selectedMonth 当前选中月份1-12
* @param today 今天的日期 * @param today 今天的日期
* @param onMonthClick 月份点击回调 * @param onMonthClick 月份点击回调
* @param sharedTransitionScope 共享元素转场作用域
* @param animatedVisibilityScope 动画可见性作用域
* @param modifier 外部布局修饰符 * @param modifier 外部布局修饰符
*/ */
@OptIn(ExperimentalSharedTransitionApi::class)
@Composable @Composable
fun YearGridView( fun YearGridView(
year: Int, year: Int,
selectedMonth: Int, selectedMonth: Int,
today: LocalDate, today: LocalDate,
onMonthClick: (Int) -> Unit, onMonthClick: (Int) -> Unit,
sharedTransitionScope: SharedTransitionScope,
animatedVisibilityScope: AnimatedVisibilityScope,
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val enterT = System.nanoTime() val enterT = System.nanoTime()
@ -176,10 +168,6 @@ fun YearGridView(
) { ) {
(0 until 3).forEach { col -> (0 until 3).forEach { col ->
val month = row * 3 + col + 1 val month = row * 3 + col + 1
with(sharedTransitionScope) {
// P0: 缓存 sharedElement tween避免每次重组创建新实例
val miniMonthTween = remember { tween<androidx.compose.ui.geometry.Rect>(400, easing = FastOutSlowInEasing) }
val seKey = "month_grid_${year}_$month"
MiniMonth( MiniMonth(
year = year, year = year,
month = month, month = month,
@ -191,17 +179,8 @@ fun YearGridView(
titleLayouts = titleLayouts, titleLayouts = titleLayouts,
weekdayLayouts = weekdayLayouts, weekdayLayouts = weekdayLayouts,
onClick = { onMonthClick(month) }, onClick = { onMonthClick(month) },
modifier = Modifier modifier = Modifier.weight(1f)
.weight(1f)
.sharedElement(
sharedContentState = rememberSharedContentState(
key = seKey
),
animatedVisibilityScope = animatedVisibilityScope,
boundsTransform = { _, _ -> miniMonthTween }
) )
)
}
} }
} }
} }