diff --git a/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarMonthPage.kt b/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarMonthPage.kt index 989e4d4..28b664c 100644 --- a/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarMonthPage.kt +++ b/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarMonthPage.kt @@ -10,6 +10,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clipToBounds +import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.dp import androidx.compose.ui.zIndex @@ -35,6 +36,7 @@ fun CalendarMonthPage( onDateClick: (LocalDate) -> Unit, collapseProgress: Float, rowHeightPx: Int, + onRowHeightMeasured: ((Int) -> Unit)? = null, modifier: Modifier = Modifier ) { val days = remember(year, month) { @@ -113,6 +115,13 @@ fun CalendarMonthPage( ) .offset(y = yOffsetDp) .padding(vertical = 4.dp) + .then( + if (weekIndex == 0 && rowHeightPx == 0) { + Modifier.onSizeChanged { size -> + if (size.height > 0) onRowHeightMeasured?.invoke(size.height) + } + } else Modifier + ) ) { week.forEach { dayData -> DayCell( diff --git a/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarMonthView.kt b/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarMonthView.kt index 1f4eee5..293a740 100644 --- a/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarMonthView.kt +++ b/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarMonthView.kt @@ -31,6 +31,7 @@ import kotlin.time.Clock import plus.rua.project.CalendarViewModel private const val START_PAGE = Int.MAX_VALUE / 2 +private const val ROW_PADDING_DP = 4 /** * 日历主界面,包含月/周视图切换和折叠动画。 @@ -51,25 +52,19 @@ fun CalendarMonthView( var currentMonth by remember { mutableIntStateOf(viewModel.currentMonth) } val density = LocalDensity.current - var calendarHeightPx by remember { mutableIntStateOf(0) } var monthHeaderHeightPx by remember { mutableIntStateOf(0) } var weekdayHeaderHeightPx by remember { mutableIntStateOf(0) } + var rowHeightPx by remember { mutableIntStateOf(0) } + @Suppress("DEPRECATION") // monthNumber 无替代 API,kotlinx-datetime 尚未提供新接口 + var currentWeeksCount by remember { mutableIntStateOf(calculateWeeksCount(today.year, today.monthNumber)) } + var screenWidthPx by remember { mutableIntStateOf(0) } var screenHeightPx by remember { mutableIntStateOf(0) } - var currentWeeksCount by remember { mutableIntStateOf(6) } - var expandedWeeksCount by remember { mutableIntStateOf(6) } - var lockedRowHeightPx by remember { mutableIntStateOf(0) } val pagerState = rememberPagerState(initialPage = START_PAGE, pageCount = { Int.MAX_VALUE }) val p = viewModel.collapseProgress val headerHeightPx = monthHeaderHeightPx + weekdayHeaderHeightPx - - // 行高:优先使用锁定值(折叠过程中不变),否则用实时计算初始化 - val rowHeightPx = if (lockedRowHeightPx > 0) { - lockedRowHeightPx - } else if (calendarHeightPx > 0 && expandedWeeksCount > 0) { - (calendarHeightPx - headerHeightPx) / expandedWeeksCount - } else 0 + val rowPaddingPx = with(density) { ROW_PADDING_DP.dp.toPx() }.toInt() // 滑动偏移插值行数 val offsetFraction by remember { derivedStateOf { pagerState.currentPageOffsetFraction } } @@ -81,24 +76,33 @@ fun CalendarMonthView( currentWeeksCount.toFloat() } + // 预估行高:DayCell aspectRatio=1,宽度 = (screenWidth - horizontalPadding) / 7 + // 加上 Row 的 vertical padding (4dp × 2) + val estimatedRowHeightPx = if (screenWidthPx > 0) { + val cellWidth = (screenWidthPx - with(density) { 32.dp.toPx() }) / 7 + val rowPadding = with(density) { 8.dp.toPx() } + (cellWidth + rowPadding).toInt() + } else 0 + + val effectiveRowHeightPx = if (rowHeightPx > 0) rowHeightPx else estimatedRowHeightPx + // 折叠时网格高度公式(与 CalendarMonthPage 一致): // gridH = rowH × (1 + (weeks-1) × (1-p)) - val gridHeightPx = if (rowHeightPx > 0) { - val rowH = rowHeightPx.toFloat() + val gridHeightPx = if (effectiveRowHeightPx > 0) { + val rowH = effectiveRowHeightPx.toFloat() val weeks = interpolatedWeeks - if (p > 0f) { + if (p > 0.01f) { (rowH * (1 + (weeks - 1) * (1f - p))).toInt() } else { (rowH * weeks).toInt() } } else 0 - val rowPaddingPx = with(density) { 4.dp.toPx() }.toInt() + val calendarAreaHeightPx = headerHeightPx + gridHeightPx + rowPaddingPx + val cardHeightPx = if (screenHeightPx > 0 && calendarAreaHeightPx > 0) screenHeightPx - calendarAreaHeightPx else 0 - val cardTopPx = headerHeightPx + gridHeightPx + rowPaddingPx - val cardHeightPx = screenHeightPx - cardTopPx - - val pagerModifier = if (p > 0.01f && rowHeightPx > 0) { + // 当 rowHeightPx 已知时,用计算的高度约束 pager;否则让 pager 自由扩展以测量行高 + val pagerModifier = if (rowHeightPx > 0 && gridHeightPx > 0) { Modifier .height(with(density) { gridHeightPx.toDp() }) .clipToBounds() @@ -111,17 +115,11 @@ fun CalendarMonthView( .fillMaxSize() .statusBarsPadding() .onSizeChanged { size -> + screenWidthPx = size.width screenHeightPx = size.height } ) { - Column(modifier = Modifier.padding(horizontal = 16.dp).onSizeChanged { size -> - calendarHeightPx = size.height - if (p < 0.01f) { - expandedWeeksCount = currentWeeksCount - val calculated = (size.height - headerHeightPx) / currentWeeksCount - if (calculated > 0) lockedRowHeightPx = calculated - } - }) { + Column(modifier = Modifier.padding(horizontal = 16.dp)) { MonthHeader( year = currentYear, month = currentMonth, @@ -133,7 +131,7 @@ fun CalendarMonthView( WeekdayHeader( modifier = Modifier.fillMaxWidth().onSizeChanged { size -> weekdayHeaderHeightPx = size.height - }.padding(bottom = 4.dp) + }.padding(bottom = ROW_PADDING_DP.dp) ) // 完全折叠且无动画时显示 WeekPager,否则显示 CalendarPager(含下拉恢复过程) if (viewModel.isCollapsed && viewModel.collapseProgress >= 1f) { @@ -166,13 +164,16 @@ fun CalendarMonthView( rowHeightPx = rowHeightPx, onWeeksChanged = { weeks -> currentWeeksCount = weeks - if (p < 0.01f) expandedWeeksCount = weeks + }, + onRowHeightMeasured = { h -> + if (h > 0 && rowHeightPx == 0) rowHeightPx = h }, pagerState = pagerState, modifier = pagerModifier ) } } + if (cardHeightPx > 0) { BottomCard( viewModel = viewModel, @@ -196,4 +197,4 @@ private fun calculateWeeksCountForPage(page: Int, today: LocalDate): Int { val year = totalMonths / 12 val month = totalMonths % 12 + 1 return calculateWeeksCount(year, month) -} \ No newline at end of file +} diff --git a/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarPager.kt b/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarPager.kt index 28031a4..a14619f 100644 --- a/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarPager.kt +++ b/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarPager.kt @@ -39,6 +39,7 @@ fun CalendarPager( collapseProgress: Float, rowHeightPx: Int, onWeeksChanged: ((Int) -> Unit)? = null, + onRowHeightMeasured: ((Int) -> Unit)? = null, pagerState: PagerState, modifier: Modifier = Modifier ) { @@ -80,7 +81,8 @@ fun CalendarPager( } }, collapseProgress = collapseProgress, - rowHeightPx = rowHeightPx + rowHeightPx = rowHeightPx, + onRowHeightMeasured = onRowHeightMeasured ) } }