refactor: 优化顶部应用栏动画速率 & 重构待办卡片样式

This commit is contained in:
Super12138 2026-02-09 08:21:13 +08:00
parent eb7fa59302
commit 6bdee1f2f7
12 changed files with 105 additions and 71 deletions

View file

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

View file

@ -47,14 +47,17 @@ object TodoDefaults {
bottomEnd = ZeroCornerSize
)*/
val ContainerColor: Color
@Composable
get() = MaterialTheme.colorScheme.surfaceBright
object Colors {
val Container: Color
@Composable
get() = MaterialTheme.colorScheme.surfaceBright
val BackgroundColor: Color
@Composable
get() = MaterialTheme.colorScheme.surfaceContainer
val Background: Color
@Composable
get() = MaterialTheme.colorScheme.surfaceContainer
val Green = Color(0xFF349938)
}
val fadedEdgeWidth = 8.dp

View file

@ -106,7 +106,7 @@ class MainActivity : ComponentActivity() {
dynamicColor = dynamicColor
) {
Surface(
color = TodoDefaults.BackgroundColor,
color = TodoDefaults.Colors.Background,
modifier = Modifier.fillMaxSize()
) {
val view = LocalView.current
@ -140,7 +140,7 @@ class MainActivity : ComponentActivity() {
)
}
},
containerColor = TodoDefaults.BackgroundColor,
containerColor = TodoDefaults.Colors.Background,
modifier = Modifier.fillMaxSize()
) {
TopNavigation(

View file

@ -130,7 +130,7 @@ fun TopAppBarScaffold(
navigationIcon = navigationIcon,
actions = actions,
colors = TopAppBarDefaults.topAppBarColors(
containerColor = TodoDefaults.BackgroundColor,
containerColor = TodoDefaults.Colors.Background,
)
)
},
@ -151,7 +151,7 @@ fun TopAppBarScaffold(
floatingActionButton: @Composable () -> Unit = {},
floatingActionButtonPosition: FabPosition = FabPosition.End,
contentWindowInsets: WindowInsets = ScaffoldDefaults.contentWindowInsets,
containerColor: Color = TodoDefaults.BackgroundColor,
containerColor: Color = TodoDefaults.Colors.Background,
screenShape: Shape = TodoDefaults.ScreenContainerShape,
content: @Composable () -> Unit
) = Scaffold(

View file

@ -16,7 +16,7 @@ fun RoundedScreenContainer(
) {
Surface(
modifier = modifier.padding(horizontal = TodoDefaults.screenHorizontalPadding),
color = TodoDefaults.BackgroundColor,
color = TodoDefaults.Colors.Background,
shape = TodoDefaults.ScreenContainerShape,
content = content
)

View file

@ -41,7 +41,7 @@ fun RoundedCornerCardLarge(
@DrawableRes iconRes: Int,
title: String,
count: Int,
containerColor: Color = TodoDefaults.ContainerColor,
containerColor: Color = TodoDefaults.Colors.Container,
shapes: ButtonShapes = TodoDefaults.shapes(),
onClick: () -> Unit = {}
) {

View file

@ -36,7 +36,7 @@ import cn.super12138.todo.utils.toRelativeTimeString
fun UpcomingTaskCard(
modifier: Modifier = Modifier,
nextWeekTodo: List<TodoEntity>,
containerColor: Color = TodoDefaults.ContainerColor
containerColor: Color = TodoDefaults.Colors.Container
) {
Card(
modifier = modifier.height(TodoDefaults.overviewCardHeight * 2),

View file

@ -37,12 +37,12 @@ fun RowSettingsItem(
title: String,
description: String? = null,
trailingContent: (@Composable () -> Unit)? = null,
background: Color = TodoDefaults.ContainerColor,
background: Color = TodoDefaults.Colors.Container,
horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
verticalAlignment: Alignment.Vertical = Alignment.Top,
scrollState: ScrollState = rememberScrollState(),
fadedEdgeWidth: Dp,
maskColor: Color = TodoDefaults.ContainerColor,
maskColor: Color = TodoDefaults.Colors.Container,
content: @Composable RowScope.() -> Unit
) {
MoreContentSettingsItem(
@ -88,11 +88,11 @@ fun LazyRowSettingsItem(
title: String,
description: String? = null,
trailingContent: (@Composable () -> Unit)? = null,
background: Color = TodoDefaults.ContainerColor,
background: Color = TodoDefaults.Colors.Container,
horizontalArrangement: Arrangement.Horizontal = Arrangement.Start,
verticalAlignment: Alignment.Vertical = Alignment.Top,
fadedEdgeWidth: Dp,
maskColor: Color = TodoDefaults.ContainerColor,
maskColor: Color = TodoDefaults.Colors.Container,
content: LazyListScope.() -> Unit
) {
MoreContentSettingsItem(
@ -137,7 +137,7 @@ fun MoreContentSettingsItem(
title: String,
description: String? = null,
trailingContent: (@Composable () -> Unit)? = null,
background: Color = TodoDefaults.ContainerColor,
background: Color = TodoDefaults.Colors.Container,
shape: CornerBasedShape = TodoDefaults.defaultShape,
content: @Composable () -> Unit
) {

View file

@ -61,7 +61,7 @@ fun SettingsItem(
title: String,
description: String? = null,
trailingContent: (@Composable () -> Unit)? = null,
background: Color = TodoDefaults.ContainerColor,
background: Color = TodoDefaults.Colors.Container,
shapes: ButtonShapes = TodoDefaults.shapes(),
enableClick: Boolean = true,
onClick: () -> Unit = {}
@ -125,7 +125,7 @@ fun SettingsItem(
title: String,
description: String? = null,
trailingContent: (@Composable () -> Unit)? = null,
background: Color = TodoDefaults.ContainerColor,
background: Color = TodoDefaults.Colors.Container,
shapes: ButtonShapes = TodoDefaults.shapes(),
enableClick: Boolean = true,
onClick: () -> Unit = {}
@ -159,7 +159,7 @@ fun SettingsItem(
title: String,
description: String? = null,
trailingContent: (@Composable () -> Unit)? = null,
background: Color = TodoDefaults.ContainerColor,
background: Color = TodoDefaults.Colors.Container,
shapes: ButtonShapes = TodoDefaults.shapes(),
enableClick: Boolean = true,
onClick: () -> Unit = {},
@ -204,7 +204,7 @@ fun SettingsItem(
headlineContent: (@Composable () -> Unit)? = null,
supportingContent: (@Composable () -> Unit)? = null,
trailingContent: (@Composable () -> Unit)? = null,
background: Color = TodoDefaults.ContainerColor,
background: Color = TodoDefaults.Colors.Container,
shapes: ButtonShapes = TodoDefaults.shapes(),
interactionSource: MutableInteractionSource? = null,
enableClick: Boolean = true,

View file

@ -126,6 +126,7 @@ fun SharedTransitionScope.TasksPage(
content = task.content,
category = task.category,
completed = task.isCompleted,
dueDate = task.dueDate,
priority = Priority.fromFloat(task.priority),
selected = selectedTodoIds.contains(task.id),
onCardClick = {

View file

@ -7,6 +7,7 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkHorizontally
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsPressedAsState
@ -14,6 +15,7 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
@ -24,7 +26,6 @@ import androidx.compose.material3.ButtonShapes
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.LocalContentColor
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
@ -37,9 +38,12 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp
import cn.super12138.todo.R
@ -50,6 +54,8 @@ import cn.super12138.todo.utils.VibrationUtils
import cn.super12138.todo.utils.containerColor
import cn.super12138.todo.utils.disabledContainerColor
import cn.super12138.todo.utils.disabledContentColor
import cn.super12138.todo.utils.toLocalDateString
import cn.super12138.todo.utils.toRelativeTimeString
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
@Composable
@ -59,6 +65,7 @@ fun TodoCard(
content: String,
category: String,
completed: Boolean,
dueDate: Long?,
priority: Priority,
selected: Boolean,
onCardClick: () -> Unit = {},
@ -67,8 +74,9 @@ fun TodoCard(
shapes: ButtonShapes = TodoDefaults.shapes(),
) {
val view = LocalView.current
val context = LocalContext.current
// TODO: 滑动删除
val cardColors = CardDefaults.cardColors(containerColor = TodoDefaults.ContainerColor)
val cardColors = CardDefaults.cardColors(containerColor = TodoDefaults.Colors.Container)
val animatedContainerColor by animateColorAsState(targetValue = if (selected) MaterialTheme.colorScheme.secondaryContainer else if (completed) cardColors.disabledContainerColor else cardColors.containerColor)
val interactionSource = remember { MutableInteractionSource() }
@ -79,6 +87,13 @@ fun TodoCard(
animationSpec = TodoDefaults.shapesDefaultAnimationSpec
)
val enterTransition = fadeIn(MaterialTheme.motionScheme.fastSpatialSpec()) + expandHorizontally(
MaterialTheme.motionScheme.fastSpatialSpec()
)
val exitTransition = fadeOut(MaterialTheme.motionScheme.fastSpatialSpec()) + shrinkHorizontally(
MaterialTheme.motionScheme.fastSpatialSpec()
)
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = modifier
@ -98,16 +113,12 @@ fun TodoCard(
.drawBehind {
drawRect(animatedContainerColor)
}
.padding(horizontal = TodoDefaults.screenHorizontalPadding)
.padding(start = TodoDefaults.screenHorizontalPadding)
) {
AnimatedVisibility(
visible = selected,
enter = fadeIn(MaterialTheme.motionScheme.fastSpatialSpec()) + expandHorizontally(
MaterialTheme.motionScheme.fastSpatialSpec()
),
exit = fadeOut(MaterialTheme.motionScheme.fastSpatialSpec()) + shrinkHorizontally(
MaterialTheme.motionScheme.fastSpatialSpec()
)
enter = enterTransition,
exit = exitTransition
) {
Box(
Modifier
@ -125,10 +136,7 @@ fun TodoCard(
}
Column(
verticalArrangement = Arrangement.spacedBy(
space = 5.dp,
alignment = Alignment.CenterVertically
),
verticalArrangement = Arrangement.Center,
modifier = Modifier
.weight(1f)
.fillMaxSize()
@ -136,13 +144,42 @@ fun TodoCard(
CompositionLocalProvider(
LocalContentColor provides if (completed) cardColors.disabledContentColor else cardColors.contentColor,
) {
Text(
text = content,
style = MaterialTheme.typography.titleLarge,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
// modifier = Modifier.basicMarquee()
)
Row(
verticalAlignment = Alignment.Top,
horizontalArrangement = Arrangement.SpaceBetween,
modifier = Modifier.fillMaxWidth()
) {
Text(
text = content,
style = MaterialTheme.typography.titleLarge,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier = Modifier.weight(1f)
)
Column(
horizontalAlignment = Alignment.End,
modifier = Modifier.padding(
start = TodoDefaults.screenVerticalPadding,
end = TodoDefaults.screenHorizontalPadding
)
) {
Text(
text = dueDate.toLocalDateString(),
style = MaterialTheme.typography.labelLarge.copy(
color = MaterialTheme.colorScheme.onSurface,
fontWeight = FontWeight.Bold
)
)
Text(
text = dueDate.toRelativeTimeString(context),
style = MaterialTheme.typography.labelSmall.copy(
color = MaterialTheme.colorScheme.onSurfaceVariant
)
)
}
}
Row(
verticalAlignment = Alignment.CenterVertically,
@ -166,35 +203,28 @@ fun TodoCard(
}
}
AnimatedVisibility(!selected && !completed) {
IconButton(
onClick = {
VibrationUtils.performHapticFeedback(view)
onChecked()
}
) {
Icon(
painter = painterResource(R.drawable.ic_check),
tint = MaterialTheme.colorScheme.primary,
contentDescription = stringResource(R.string.tip_mark_completed)
)
}
/*Box(
AnimatedVisibility(
visible = !selected && !completed,
enter = enterTransition,
exit = exitTransition
) {
Box(
contentAlignment = Alignment.Center,
modifier = Modifier
.width(50.dp)
.fillMaxHeight()
.background(MaterialTheme.colorScheme.tertiaryContainer)
.background(TodoDefaults.Colors.Green)
.clickable {
VibrationUtils.performHapticFeedback(view)
onChecked()
}
) {
Icon(
imageVector = Icons.Outlined.Check,
tint = MaterialTheme.colorScheme.primary,
contentDescription = ""
painter = painterResource(R.drawable.ic_check),
tint = Color.White,
contentDescription = null,
modifier = Modifier.padding(TodoDefaults.screenHorizontalPadding)
)
}*/
}
}
}
}

View file

@ -46,23 +46,23 @@ fun TodoTopAppBar(
modifier: Modifier = Modifier
) {
val navIconEnterTransition = fadeIn(
animationSpec = MaterialTheme.motionScheme.defaultEffectsSpec()
animationSpec = MaterialTheme.motionScheme.fastEffectsSpec()
) + expandIn(
animationSpec = MaterialTheme.motionScheme.defaultSpatialSpec(),
animationSpec = MaterialTheme.motionScheme.fastSpatialSpec(),
expandFrom = Alignment.CenterStart
)
val navIconExitTransition = fadeOut(
animationSpec = MaterialTheme.motionScheme.defaultEffectsSpec()
animationSpec = MaterialTheme.motionScheme.fastEffectsSpec()
) + shrinkOut(
animationSpec = MaterialTheme.motionScheme.defaultSpatialSpec(),
animationSpec = MaterialTheme.motionScheme.fastSpatialSpec(),
shrinkTowards = Alignment.CenterStart
)
val enterTransition = fadeIn(MaterialTheme.motionScheme.defaultEffectsSpec()) +
val enterTransition = fadeIn(MaterialTheme.motionScheme.fastEffectsSpec()) +
scaleIn(
animationSpec = MaterialTheme.motionScheme.defaultSpatialSpec(),
animationSpec = MaterialTheme.motionScheme.fastSpatialSpec(),
initialScale = 0.92f
)
val exitTransition = fadeOut(MaterialTheme.motionScheme.defaultEffectsSpec())
val exitTransition = fadeOut(MaterialTheme.motionScheme.fastEffectsSpec())
val titleTransition = ContentTransform(
targetContentEnter = enterTransition,
initialContentExit = exitTransition
@ -74,7 +74,7 @@ fun TodoTopAppBar(
targetValue = if (selectedMode) {
MaterialTheme.colorScheme.surfaceContainerHighest
} else {
TodoDefaults.BackgroundColor
TodoDefaults.Colors.Background
}
)