feat: 法定假日背景添加波浪缩放动画

点击"显示调休"后,假日格子背景从左上到右下依次缩放弹出(每格延迟15ms),
关闭时反向缩放消失,使用 graphicsLayer 实现高性能动画。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
xfy 2026-05-27 17:41:18 +08:00
parent 3c1a04580c
commit 6dffaf4c91
3 changed files with 27 additions and 2 deletions

View File

@ -253,7 +253,7 @@ private fun WeekRow(
) )
.padding(vertical = ROW_PADDING_DP.dp) .padding(vertical = ROW_PADDING_DP.dp)
) { ) {
week.forEach { dayData -> week.forEachIndexed { dayIndex, dayData ->
key(dayData.date) { key(dayData.date) {
DayCell( DayCell(
date = dayData.date, date = dayData.date,
@ -263,6 +263,7 @@ private fun WeekRow(
shiftKind = shiftKindAt(dayData.date), shiftKind = shiftKindAt(dayData.date),
showLegalHoliday = showLegalHoliday, showLegalHoliday = showLegalHoliday,
holidayEdgeInfo = holidayEdges[dayData.date], holidayEdgeInfo = holidayEdges[dayData.date],
cellIndex = weekIndex * 7 + dayIndex,
onClick = { onDateClick(dayData.date) }, onClick = { onDateClick(dayData.date) },
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
interactionSource = interactionSource, interactionSource = interactionSource,

View File

@ -3,8 +3,11 @@ package plus.rua.project.ui
import androidx.compose.animation.animateColor import androidx.compose.animation.animateColor
import androidx.compose.animation.core.FastOutSlowInEasing import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.animateFloat import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.animation.core.updateTransition import androidx.compose.animation.core.updateTransition
import androidx.compose.ui.graphics.TransformOrigin
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource import androidx.compose.foundation.interaction.MutableInteractionSource
@ -57,6 +60,7 @@ enum class DayCellState {
* false(默认):排班放右上角,不显示法定调休背景 * false(默认):排班放右上角,不显示法定调休背景
* true:排班仍在右上角,法定假日以淡色背景显示(""淡红,""淡蓝) * true:排班仍在右上角,法定假日以淡色背景显示(""淡红,""淡蓝)
* @param holidayEdgeInfo 假日在连续序列中的边缘状态,决定背景圆角null 表示无假日 * @param holidayEdgeInfo 假日在连续序列中的边缘状态,决定背景圆角null 表示无假日
* @param cellIndex 单元格在月网格中的线性索引(weekIndex*7+dayIndex),用于法定假日波浪动画延迟
* @param onClick 点击回调 * @param onClick 点击回调
* @param modifier 外部布局修饰符 * @param modifier 外部布局修饰符
*/ */
@ -69,6 +73,7 @@ fun DayCell(
shiftKind: ShiftKind?, shiftKind: ShiftKind?,
showLegalHoliday: Boolean, showLegalHoliday: Boolean,
holidayEdgeInfo: HolidayEdgeInfo? = null, holidayEdgeInfo: HolidayEdgeInfo? = null,
cellIndex: Int = 0,
onClick: () -> Unit, onClick: () -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
interactionSource: MutableInteractionSource = remember { MutableInteractionSource() }, interactionSource: MutableInteractionSource = remember { MutableInteractionSource() },
@ -84,6 +89,7 @@ fun DayCell(
shiftKind = shiftKind, shiftKind = shiftKind,
showLegalHoliday = showLegalHoliday, showLegalHoliday = showLegalHoliday,
holidayEdgeInfo = holidayEdgeInfo, holidayEdgeInfo = holidayEdgeInfo,
cellIndex = cellIndex,
onClick = onClick, onClick = onClick,
modifier = modifier, modifier = modifier,
interactionSource = interactionSource, interactionSource = interactionSource,
@ -105,6 +111,7 @@ fun DayCell(
shiftKind = shiftKind, shiftKind = shiftKind,
showLegalHoliday = showLegalHoliday, showLegalHoliday = showLegalHoliday,
holidayEdgeInfo = holidayEdgeInfo, holidayEdgeInfo = holidayEdgeInfo,
cellIndex = cellIndex,
onClick = onClick, onClick = onClick,
modifier = modifier, modifier = modifier,
interactionSource = interactionSource, interactionSource = interactionSource,
@ -122,6 +129,7 @@ private fun DayCellImpl(
shiftKind: ShiftKind?, shiftKind: ShiftKind?,
showLegalHoliday: Boolean, showLegalHoliday: Boolean,
holidayEdgeInfo: HolidayEdgeInfo?, holidayEdgeInfo: HolidayEdgeInfo?,
cellIndex: Int,
onClick: () -> Unit, onClick: () -> Unit,
modifier: Modifier, modifier: Modifier,
interactionSource: MutableInteractionSource, interactionSource: MutableInteractionSource,
@ -220,11 +228,21 @@ private fun DayCellImpl(
else -> Color.Transparent else -> Color.Transparent
} }
val holidayScale by animateFloatAsState(
targetValue = if (showLegalHoliday && holidayBadge != null) 1f else 0f,
animationSpec = tween(
durationMillis = 200,
delayMillis = cellIndex * 15,
easing = FastOutSlowInEasing
),
label = "holidayScale"
)
Box( Box(
modifier = modifier.aspectRatio(1f) modifier = modifier.aspectRatio(1f)
) { ) {
// 法定假日背景(最底层,与选中/今天状态叠加) // 法定假日背景(最底层,与选中/今天状态叠加)
if (showLegalHoliday && holidayBadge != null) { if (holidayScale > 0f) {
val holidayShape = when { val holidayShape = when {
holidayEdgeInfo?.isStart == true && holidayEdgeInfo.isEnd -> RoundedCornerShape(8.dp) holidayEdgeInfo?.isStart == true && holidayEdgeInfo.isEnd -> RoundedCornerShape(8.dp)
holidayEdgeInfo?.isStart == true -> RoundedCornerShape(topStart = 8.dp, bottomStart = 8.dp) holidayEdgeInfo?.isStart == true -> RoundedCornerShape(topStart = 8.dp, bottomStart = 8.dp)
@ -235,6 +253,11 @@ private fun DayCellImpl(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(horizontal = 0.5.dp) .padding(horizontal = 0.5.dp)
.graphicsLayer {
scaleX = holidayScale
scaleY = holidayScale
transformOrigin = TransformOrigin.Center
}
.background(holidayBgColor, holidayShape) .background(holidayBgColor, holidayShape)
) )
} }

View File

@ -112,6 +112,7 @@ fun WeekPager(
isToday = date == today, isToday = date == today,
shiftKind = shiftKindAt(date), shiftKind = shiftKindAt(date),
showLegalHoliday = showLegalHoliday, showLegalHoliday = showLegalHoliday,
cellIndex = dayOffset,
onClick = { onDateClick(date) }, onClick = { onDateClick(date) },
modifier = Modifier.weight(1f), modifier = Modifier.weight(1f),
interactionSource = interactionSource, interactionSource = interactionSource,