修复年视图布局和动画问题
- 年视图每个小月历添加星期行头部 - 日期列用 weight(1f) 对齐,去掉 CircleShape 裁剪 - 取消前一个动画 Job 防止快速点击时动画丢失
This commit is contained in:
parent
8dad07c0a0
commit
142d0c235a
@ -8,6 +8,7 @@ import androidx.compose.runtime.getValue
|
|||||||
import androidx.compose.runtime.mutableStateOf
|
import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Job
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.datetime.DatePeriod
|
import kotlinx.datetime.DatePeriod
|
||||||
import kotlinx.datetime.LocalDate
|
import kotlinx.datetime.LocalDate
|
||||||
@ -58,6 +59,8 @@ class CalendarViewModel(
|
|||||||
private val _collapseAnimatable = Animatable(0f)
|
private val _collapseAnimatable = Animatable(0f)
|
||||||
val collapseProgress: Float get() = _collapseAnimatable.value
|
val collapseProgress: Float get() = _collapseAnimatable.value
|
||||||
|
|
||||||
|
private var yearViewJob: Job? = null
|
||||||
|
|
||||||
@Suppress("DEPRECATION") // monthNumber 无替代 API,kotlinx-datetime 尚未提供新接口
|
@Suppress("DEPRECATION") // monthNumber 无替代 API,kotlinx-datetime 尚未提供新接口
|
||||||
val currentMonth: Int get() = selectedDate.month.number
|
val currentMonth: Int get() = selectedDate.month.number
|
||||||
|
|
||||||
@ -87,7 +90,8 @@ class CalendarViewModel(
|
|||||||
*/
|
*/
|
||||||
fun toggleYearView() {
|
fun toggleYearView() {
|
||||||
if (isCollapsed) return
|
if (isCollapsed) return
|
||||||
coroutineScope.launch {
|
yearViewJob?.cancel()
|
||||||
|
yearViewJob = coroutineScope.launch {
|
||||||
if (isYearView) {
|
if (isYearView) {
|
||||||
_yearViewAnimatable.animateTo(
|
_yearViewAnimatable.animateTo(
|
||||||
0f, tween(400, easing = FastOutSlowInEasing)
|
0f, tween(400, easing = FastOutSlowInEasing)
|
||||||
@ -112,7 +116,8 @@ class CalendarViewModel(
|
|||||||
val date = if (yearViewYear == today.year && today.month.number == month) today
|
val date = if (yearViewYear == today.year && today.month.number == month) today
|
||||||
else LocalDate(yearViewYear, month, 1)
|
else LocalDate(yearViewYear, month, 1)
|
||||||
selectedDate = date
|
selectedDate = date
|
||||||
coroutineScope.launch {
|
yearViewJob?.cancel()
|
||||||
|
yearViewJob = coroutineScope.launch {
|
||||||
_yearViewAnimatable.animateTo(
|
_yearViewAnimatable.animateTo(
|
||||||
0f, tween(400, easing = FastOutSlowInEasing)
|
0f, tween(400, easing = FastOutSlowInEasing)
|
||||||
)
|
)
|
||||||
|
|||||||
@ -27,16 +27,18 @@ import kotlinx.datetime.LocalDate
|
|||||||
import kotlinx.datetime.minus
|
import kotlinx.datetime.minus
|
||||||
import kotlinx.datetime.number
|
import kotlinx.datetime.number
|
||||||
import kotlinx.datetime.plus
|
import kotlinx.datetime.plus
|
||||||
import kotlinx.datetime.todayIn
|
|
||||||
|
private val WEEKDAY_LABELS = listOf("一", "二", "三", "四", "五", "六", "日")
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 年度网格视图,显示 4×3 精简月历网格,支持年份切换。
|
* 年度网格视图,显示 4×3 精简月历网格,支持年份切换。
|
||||||
*
|
*
|
||||||
* 每格显示一个精简版月历(月份标题 + 日期数字网格),
|
* 每格显示一个精简版月历(月份标题 + 星期行 + 日期数字网格),
|
||||||
* 选中月份高亮,点击进入该月。
|
* 选中月份高亮,点击进入该月。
|
||||||
*
|
*
|
||||||
* @param year 显示的年份
|
* @param year 显示的年份
|
||||||
* @param selectedMonth 当前选中月份(1-12)
|
* @param selectedMonth 当前选中月份(1-12)
|
||||||
|
* @param today 今天的日期
|
||||||
* @param onMonthClick 月份点击回调
|
* @param onMonthClick 月份点击回调
|
||||||
* @param onYearChange 年份切换回调
|
* @param onYearChange 年份切换回调
|
||||||
* @param modifier 外部布局修饰符
|
* @param modifier 外部布局修饰符
|
||||||
@ -95,7 +97,7 @@ fun YearGridView(
|
|||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
.fillMaxWidth()
|
.fillMaxWidth()
|
||||||
.weight(1f)
|
.weight(1f)
|
||||||
.padding(horizontal = 8.dp),
|
.padding(horizontal = 4.dp),
|
||||||
verticalArrangement = Arrangement.SpaceEvenly
|
verticalArrangement = Arrangement.SpaceEvenly
|
||||||
) {
|
) {
|
||||||
(0 until 4).forEach { row ->
|
(0 until 4).forEach { row ->
|
||||||
@ -121,7 +123,7 @@ fun YearGridView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 精简版月历:月份标题 + 日期数字网格。
|
* 精简版月历:月份标题 + 星期行 + 日期数字网格。
|
||||||
*/
|
*/
|
||||||
@Composable
|
@Composable
|
||||||
private fun MiniMonth(
|
private fun MiniMonth(
|
||||||
@ -138,6 +140,7 @@ private fun MiniMonth(
|
|||||||
} else {
|
} else {
|
||||||
MaterialTheme.colorScheme.onSurface
|
MaterialTheme.colorScheme.onSurface
|
||||||
}
|
}
|
||||||
|
val weekdayColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.4f)
|
||||||
val dayColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f)
|
val dayColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.6f)
|
||||||
val otherMonthColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.2f)
|
val otherMonthColor = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.2f)
|
||||||
val todayBgColor = MaterialTheme.colorScheme.primary
|
val todayBgColor = MaterialTheme.colorScheme.primary
|
||||||
@ -145,19 +148,33 @@ private fun MiniMonth(
|
|||||||
Column(
|
Column(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
.padding(2.dp)
|
.padding(2.dp)
|
||||||
.clip(CircleShape)
|
|
||||||
.clickable(onClick = onClick)
|
.clickable(onClick = onClick)
|
||||||
.padding(vertical = 4.dp),
|
.padding(vertical = 2.dp),
|
||||||
horizontalAlignment = Alignment.CenterHorizontally
|
horizontalAlignment = Alignment.CenterHorizontally
|
||||||
) {
|
) {
|
||||||
// 月份标题
|
// 月份标题
|
||||||
Text(
|
Text(
|
||||||
text = "${month}月",
|
text = "${month}月",
|
||||||
color = titleColor,
|
color = titleColor,
|
||||||
fontSize = 10.sp,
|
fontSize = 9.sp,
|
||||||
fontWeight = if (isSelected) FontWeight.Bold else FontWeight.Normal,
|
fontWeight = if (isSelected) FontWeight.Bold else FontWeight.Normal,
|
||||||
textAlign = TextAlign.Center
|
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 ->
|
days.chunked(7).forEach { week ->
|
||||||
Row(
|
Row(
|
||||||
@ -165,14 +182,15 @@ private fun MiniMonth(
|
|||||||
horizontalArrangement = Arrangement.SpaceEvenly
|
horizontalArrangement = Arrangement.SpaceEvenly
|
||||||
) {
|
) {
|
||||||
week.forEach { dayData ->
|
week.forEach { dayData ->
|
||||||
val isToday = dayData.date == today
|
val isToday = dayData.date == today && dayData.isCurrentMonth
|
||||||
val color = when {
|
val color = when {
|
||||||
!dayData.isCurrentMonth -> otherMonthColor
|
!dayData.isCurrentMonth -> otherMonthColor
|
||||||
isToday -> MaterialTheme.colorScheme.primary
|
isToday -> MaterialTheme.colorScheme.onPrimary
|
||||||
else -> dayColor
|
else -> dayColor
|
||||||
}
|
}
|
||||||
Box(
|
Box(
|
||||||
contentAlignment = Alignment.Center
|
contentAlignment = Alignment.Center,
|
||||||
|
modifier = Modifier.weight(1f)
|
||||||
) {
|
) {
|
||||||
if (isToday) {
|
if (isToday) {
|
||||||
Box(
|
Box(
|
||||||
@ -189,10 +207,10 @@ private fun MiniMonth(
|
|||||||
}
|
}
|
||||||
Text(
|
Text(
|
||||||
text = if (dayData.isCurrentMonth) dayData.date.day.toString() else "",
|
text = if (dayData.isCurrentMonth) dayData.date.day.toString() else "",
|
||||||
color = if (isToday) MaterialTheme.colorScheme.onPrimary else color,
|
color = color,
|
||||||
fontSize = 7.sp,
|
fontSize = 6.sp,
|
||||||
textAlign = TextAlign.Center,
|
textAlign = TextAlign.Center,
|
||||||
lineHeight = 10.sp
|
lineHeight = 9.sp
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user