refactor: 优化动画曲线 & 颜色变换动画性能

This commit is contained in:
Super12138 2026-02-08 23:10:55 +08:00
parent c33ed5d048
commit eb7fa59302
3 changed files with 54 additions and 26 deletions

View file

@ -38,7 +38,7 @@ android {
applicationId = "cn.super12138.todo"
minSdk = 24
targetSdk = 36
versionCode = 985
versionCode = 986
versionName = "2.3.3"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"

View file

@ -15,6 +15,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.imePadding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@ -85,6 +86,7 @@ fun SharedTransitionScope.TodoEditPage(
onNavigateUp = onNavigateUp
)
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun SharedTransitionScope.TodoEditorPage(
modifier: Modifier = Modifier,
@ -210,8 +212,12 @@ fun SharedTransitionScope.TodoEditorPage(
AnimatedVisibility(
visible = isCustomCategory,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically()
enter = fadeIn(MaterialTheme.motionScheme.defaultEffectsSpec()) + expandVertically(
MaterialTheme.motionScheme.defaultEffectsSpec()
),
exit = fadeOut(MaterialTheme.motionScheme.defaultEffectsSpec()) + shrinkVertically(
MaterialTheme.motionScheme.defaultEffectsSpec()
)
) {
TodoCategoryTextField(
value = uiState.categoryContent,

View file

@ -2,16 +2,16 @@ package cn.super12138.todo.ui.pages.tasks.components
import androidx.compose.animation.AnimatedContent
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.ContentTransform
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.tween
import androidx.compose.animation.expandIn
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.shrinkOut
import androidx.compose.animation.togetherWith
import androidx.compose.foundation.layout.Row
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.MaterialTheme
@ -22,9 +22,10 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
@ -34,7 +35,7 @@ import cn.super12138.todo.R
import cn.super12138.todo.ui.TodoDefaults
import cn.super12138.todo.utils.VibrationUtils
@OptIn(ExperimentalMaterial3Api::class)
@OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterial3ExpressiveApi::class)
@Composable
fun TodoTopAppBar(
selectedTodoIds: List<Int>,
@ -44,8 +45,32 @@ fun TodoTopAppBar(
onDeleteSelectedTodo: () -> Unit,
modifier: Modifier = Modifier
) {
val navIconEnterTransition = fadeIn(
animationSpec = MaterialTheme.motionScheme.defaultEffectsSpec()
) + expandIn(
animationSpec = MaterialTheme.motionScheme.defaultSpatialSpec(),
expandFrom = Alignment.CenterStart
)
val navIconExitTransition = fadeOut(
animationSpec = MaterialTheme.motionScheme.defaultEffectsSpec()
) + shrinkOut(
animationSpec = MaterialTheme.motionScheme.defaultSpatialSpec(),
shrinkTowards = Alignment.CenterStart
)
val enterTransition = fadeIn(MaterialTheme.motionScheme.defaultEffectsSpec()) +
scaleIn(
animationSpec = MaterialTheme.motionScheme.defaultSpatialSpec(),
initialScale = 0.92f
)
val exitTransition = fadeOut(MaterialTheme.motionScheme.defaultEffectsSpec())
val titleTransition = ContentTransform(
targetContentEnter = enterTransition,
initialContentExit = exitTransition
)
val view = LocalView.current
val animatedTopAppBarColors by animateColorAsState(
val animatedContainerColor by animateColorAsState(
animationSpec = MaterialTheme.motionScheme.defaultEffectsSpec(),
targetValue = if (selectedMode) {
MaterialTheme.colorScheme.surfaceContainerHighest
} else {
@ -57,8 +82,8 @@ fun TodoTopAppBar(
navigationIcon = {
AnimatedVisibility(
visible = selectedMode,
enter = fadeIn() + expandIn(expandFrom = Alignment.CenterStart),
exit = shrinkOut(shrinkTowards = Alignment.CenterStart) + fadeOut()
enter = navIconEnterTransition,
exit = navIconExitTransition
) {
IconButton(
onClick = {
@ -76,14 +101,7 @@ fun TodoTopAppBar(
title = {
AnimatedContent(
targetState = !selectedMode,
transitionSpec = {
(
fadeIn(animationSpec = tween(100)) +
scaleIn(initialScale = 0.92f)
).togetherWith(
fadeOut(animationSpec = tween(100))
)
}
transitionSpec = { titleTransition }
) {
if (it) {
Text(
@ -104,7 +122,11 @@ fun TodoTopAppBar(
}
},
actions = {
AnimatedVisibility(visible = selectedMode) {
AnimatedVisibility(
visible = selectedMode,
enter = enterTransition,
exit = exitTransition
) {
Row {
IconButton(
onClick = {
@ -132,21 +154,21 @@ fun TodoTopAppBar(
}
},
colors = TopAppBarDefaults.topAppBarColors().copy(
containerColor = animatedTopAppBarColors
),
modifier = modifier
colors = TopAppBarDefaults.topAppBarColors().copy(containerColor = Color.Transparent),
modifier = modifier.drawBehind {
drawRect(animatedContainerColor)
}
)
}
@Preview(locale = "zh-rCN", showBackground = true)
@Composable
private fun TodoTopAppBarPreview() {
var selectedMode by remember { mutableStateOf(false) }
val selectedMode = remember { mutableStateOf(false) }
TodoTopAppBar(
selectedTodoIds = (1..10).toList(),
selectedMode = selectedMode,
onCancelSelect = { selectedMode = !selectedMode },
selectedMode = selectedMode.value,
onCancelSelect = { selectedMode.value = !selectedMode.value },
onSelectAll = { },
onDeleteSelectedTodo = { }
)