From 142d0c235a45820977cd8298941ba8aa69fff41d Mon Sep 17 00:00:00 2001 From: meyou <2636699780@qq.com> Date: Sat, 16 May 2026 16:49:10 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=B9=B4=E8=A7=86=E5=9B=BE?= =?UTF-8?q?=E5=B8=83=E5=B1=80=E5=92=8C=E5=8A=A8=E7=94=BB=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 年视图每个小月历添加星期行头部 - 日期列用 weight(1f) 对齐,去掉 CircleShape 裁剪 - 取消前一个动画 Job 防止快速点击时动画丢失 --- .../plus/rua/project/CalendarViewModel.kt | 9 +++- .../plus/rua/project/ui/YearGridView.kt | 44 +++++++++++++------ 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/shared/src/commonMain/kotlin/plus/rua/project/CalendarViewModel.kt b/shared/src/commonMain/kotlin/plus/rua/project/CalendarViewModel.kt index 94e057a..29d3a68 100644 --- a/shared/src/commonMain/kotlin/plus/rua/project/CalendarViewModel.kt +++ b/shared/src/commonMain/kotlin/plus/rua/project/CalendarViewModel.kt @@ -8,6 +8,7 @@ import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.setValue import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.Job import kotlinx.coroutines.launch import kotlinx.datetime.DatePeriod import kotlinx.datetime.LocalDate @@ -58,6 +59,8 @@ class CalendarViewModel( private val _collapseAnimatable = Animatable(0f) val collapseProgress: Float get() = _collapseAnimatable.value + private var yearViewJob: Job? = null + @Suppress("DEPRECATION") // monthNumber 无替代 API,kotlinx-datetime 尚未提供新接口 val currentMonth: Int get() = selectedDate.month.number @@ -87,7 +90,8 @@ class CalendarViewModel( */ fun toggleYearView() { if (isCollapsed) return - coroutineScope.launch { + yearViewJob?.cancel() + yearViewJob = coroutineScope.launch { if (isYearView) { _yearViewAnimatable.animateTo( 0f, tween(400, easing = FastOutSlowInEasing) @@ -112,7 +116,8 @@ class CalendarViewModel( val date = if (yearViewYear == today.year && today.month.number == month) today else LocalDate(yearViewYear, month, 1) selectedDate = date - coroutineScope.launch { + yearViewJob?.cancel() + yearViewJob = coroutineScope.launch { _yearViewAnimatable.animateTo( 0f, tween(400, easing = FastOutSlowInEasing) ) diff --git a/shared/src/commonMain/kotlin/plus/rua/project/ui/YearGridView.kt b/shared/src/commonMain/kotlin/plus/rua/project/ui/YearGridView.kt index abb18bb..4fae310 100644 --- a/shared/src/commonMain/kotlin/plus/rua/project/ui/YearGridView.kt +++ b/shared/src/commonMain/kotlin/plus/rua/project/ui/YearGridView.kt @@ -27,16 +27,18 @@ import kotlinx.datetime.LocalDate import kotlinx.datetime.minus import kotlinx.datetime.number import kotlinx.datetime.plus -import kotlinx.datetime.todayIn + +private val WEEKDAY_LABELS = listOf("一", "二", "三", "四", "五", "六", "日") /** * 年度网格视图,显示 4×3 精简月历网格,支持年份切换。 * - * 每格显示一个精简版月历(月份标题 + 日期数字网格), + * 每格显示一个精简版月历(月份标题 + 星期行 + 日期数字网格), * 选中月份高亮,点击进入该月。 * * @param year 显示的年份 * @param selectedMonth 当前选中月份(1-12) + * @param today 今天的日期 * @param onMonthClick 月份点击回调 * @param onYearChange 年份切换回调 * @param modifier 外部布局修饰符 @@ -95,7 +97,7 @@ fun YearGridView( modifier = Modifier .fillMaxWidth() .weight(1f) - .padding(horizontal = 8.dp), + .padding(horizontal = 4.dp), verticalArrangement = Arrangement.SpaceEvenly ) { (0 until 4).forEach { row -> @@ -121,7 +123,7 @@ fun YearGridView( } /** - * 精简版月历:月份标题 + 日期数字网格。 + * 精简版月历:月份标题 + 星期行 + 日期数字网格。 */ @Composable private fun MiniMonth( @@ -138,6 +140,7 @@ private fun MiniMonth( } else { MaterialTheme.colorScheme.onSurface } + val weekdayColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.4f) val dayColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f) val otherMonthColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.2f) val todayBgColor = MaterialTheme.colorScheme.primary @@ -145,19 +148,33 @@ private fun MiniMonth( Column( modifier = modifier .padding(2.dp) - .clip(CircleShape) .clickable(onClick = onClick) - .padding(vertical = 4.dp), + .padding(vertical = 2.dp), horizontalAlignment = Alignment.CenterHorizontally ) { // 月份标题 Text( text = "${month}月", color = titleColor, - fontSize = 10.sp, + fontSize = 9.sp, fontWeight = if (isSelected) FontWeight.Bold else FontWeight.Normal, textAlign = TextAlign.Center ) + // 星期行 + Row( + modifier = Modifier.fillMaxWidth(), + horizontalArrangement = Arrangement.SpaceEvenly + ) { + WEEKDAY_LABELS.forEach { label -> + Text( + text = label, + color = weekdayColor, + fontSize = 6.sp, + textAlign = TextAlign.Center, + modifier = Modifier.weight(1f) + ) + } + } // 日期网格 days.chunked(7).forEach { week -> Row( @@ -165,14 +182,15 @@ private fun MiniMonth( horizontalArrangement = Arrangement.SpaceEvenly ) { week.forEach { dayData -> - val isToday = dayData.date == today + val isToday = dayData.date == today && dayData.isCurrentMonth val color = when { !dayData.isCurrentMonth -> otherMonthColor - isToday -> MaterialTheme.colorScheme.primary + isToday -> MaterialTheme.colorScheme.onPrimary else -> dayColor } Box( - contentAlignment = Alignment.Center + contentAlignment = Alignment.Center, + modifier = Modifier.weight(1f) ) { if (isToday) { Box( @@ -189,10 +207,10 @@ private fun MiniMonth( } Text( text = if (dayData.isCurrentMonth) dayData.date.day.toString() else "", - color = if (isToday) MaterialTheme.colorScheme.onPrimary else color, - fontSize = 7.sp, + color = color, + fontSize = 6.sp, textAlign = TextAlign.Center, - lineHeight = 10.sp + lineHeight = 9.sp ) } }