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 11faf16..c106eeb 100644 --- a/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarMonthPage.kt +++ b/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarMonthPage.kt @@ -1,6 +1,6 @@ package plus.rua.project.ui -import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height @@ -42,37 +42,68 @@ fun CalendarMonthPage( weeks.indexOfFirst { week -> week.any { it.date == selectedDate } } } + val hasSelectedWeek = selectedWeekIndex >= 0 + var rowHeightPx by remember { mutableIntStateOf(0) } val rowMeasured = rowHeightPx > 0 + val H = rowHeightPx.toFloat() - // 选中行上移距离 = 上方行数 × 行高 × progress - val selectedOffsetPx = if (rowMeasured) { - -(selectedWeekIndex.toFloat() * rowHeightPx.toFloat() * collapseProgress) + // 总高度 = 6行 × 行高(展开时),或选中行高度(折叠时) + val totalHeightDp = if (rowMeasured) { + if (hasSelectedWeek) { + // 选中行高度 + 上方行压缩高度 + 下方行压缩高度 + val aboveH = selectedWeekIndex * H * (1f - collapseProgress) + val belowH = (weeks.size - 1 - selectedWeekIndex) * H * (1f - collapseProgress) + val selH = H + with(density) { (aboveH + selH + belowH).toDp() } + } else { + with(density) { (weeks.size * H).toDp() } + } } else { - 0f + null } - val selectedOffsetDp = with(density) { selectedOffsetPx.toDp() } - Column(modifier = modifier.clipToBounds()) { + Box(modifier = modifier.clipToBounds().then( + if (totalHeightDp != null) Modifier.height(totalHeightDp) + else Modifier + ).onSizeChanged { size -> + if (collapseProgress > 0f) { + println("[Page] totalH=${size.height}px p=$collapseProgress selWeek=$selectedWeekIndex rowH=$rowHeightPx") + } + }) { weeks.forEachIndexed { weekIndex, week -> - val isSelected = weekIndex == selectedWeekIndex - val isAboveSelected = weekIndex < selectedWeekIndex - val isBelowSelected = weekIndex > selectedWeekIndex + val isSelected = hasSelectedWeek && weekIndex == selectedWeekIndex + val isAbove = hasSelectedWeek && weekIndex < selectedWeekIndex + val isBelow = hasSelectedWeek && weekIndex > selectedWeekIndex - // 非选中行高度跟手压缩 val rowScale = when { - isAboveSelected || isBelowSelected -> 1f - collapseProgress + isAbove || isBelow -> 1f - collapseProgress else -> 1f } val rowHeightDp = if (rowMeasured && rowScale > 0.01f) { - with(density) { (rowHeightPx.toFloat() * rowScale).toDp() } + with(density) { (H * rowScale).toDp() } } else if (!rowMeasured) { null } else { 0.dp } + // 手动计算每行的视觉 y 位置 + val yOffsetDp = if (rowMeasured && hasSelectedWeek) { + val yPx = when { + isAbove -> weekIndex * H * (1f - collapseProgress) + isSelected -> selectedWeekIndex * H * (1f - collapseProgress) + isBelow -> selectedWeekIndex * H * (1f - collapseProgress) + H + (weekIndex - selectedWeekIndex - 1) * H * (1f - collapseProgress) + else -> weekIndex * H + } + with(density) { yPx.toDp() } + } else if (rowMeasured) { + with(density) { (weekIndex * H).toDp() } + } else { + 0.dp + } + val shouldShow = rowHeightDp == null || rowHeightDp > 0.dp if (shouldShow) { @@ -84,10 +115,7 @@ fun CalendarMonthPage( if (rowHeightDp != null) Modifier.height(rowHeightDp) else Modifier ) - .then( - if (isSelected && rowMeasured) Modifier.offset(y = selectedOffsetDp) - else Modifier - ) + .offset(y = yOffsetDp) .onSizeChanged { size -> if (size.height > 0 && !rowMeasured) { rowHeightPx = size.height 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 a182629..b65ec27 100644 --- a/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarMonthView.kt +++ b/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarMonthView.kt @@ -5,7 +5,6 @@ import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.runtime.Composable @@ -19,7 +18,6 @@ import androidx.compose.ui.Modifier import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.unit.dp -import kotlinx.datetime.LocalDate import kotlinx.datetime.TimeZone import kotlinx.datetime.todayIn import kotlin.time.Clock @@ -44,26 +42,34 @@ fun CalendarMonthView( val density = LocalDensity.current var calendarHeightPx by remember { mutableIntStateOf(0) } - var screenHeightPx by remember { mutableIntStateOf(0) } - var expandedCalendarHeightPx by remember { mutableIntStateOf(0) } var monthHeaderHeightPx by remember { mutableIntStateOf(0) } var weekdayHeaderHeightPx by remember { mutableIntStateOf(0) } + var screenHeightPx by remember { mutableIntStateOf(0) } - // 日历网格高度 = 总高度 - MonthHeader - WeekdayHeader - val expandedGridHeightPx = expandedCalendarHeightPx - monthHeaderHeightPx - weekdayHeaderHeightPx - // 折叠偏移量 = 进度 × 网格5行高度(保留1行可见) - val collapseOffsetPx = if (viewModel.isCollapsed) { - 0 - } else { - -(viewModel.collapseProgress * expandedGridHeightPx * 5f / 6f).toInt() - } - val cardTopPx = if (viewModel.isCollapsed) { - calendarHeightPx - } else { - expandedCalendarHeightPx + collapseOffsetPx - } + val p = viewModel.collapseProgress + val headerHeightPx = monthHeaderHeightPx + weekdayHeaderHeightPx + + // 展开时网格高度 = 首次测量的日历总高度 - headers + val expandedGridHeightPx = calendarHeightPx - headerHeightPx + val weeksCount = 6 + + // 折叠时网格高度公式(与 CalendarMonthPage 一致): + // gridH = rowH × (1 + (weeks-1) × (1-p)) + // 其中 rowH = expandedGridHeightPx / weeksCount + val gridHeightPx = if (expandedGridHeightPx > 0 && p > 0f) { + val rowH = expandedGridHeightPx.toFloat() / weeksCount + (rowH * (1 + (weeksCount - 1) * (1f - p))).toInt() + } else if (expandedGridHeightPx > 0) { + expandedGridHeightPx + } else 0 + + val cardTopPx = headerHeightPx + gridHeightPx val cardHeightPx = screenHeightPx - cardTopPx + if (p > 0f) { + println("[View] p=$p monthH=$monthHeaderHeightPx weekdayH=$weekdayHeaderHeightPx expandedGridH=$expandedGridHeightPx gridH=$gridHeightPx cardTop=$cardTopPx cardH=$cardHeightPx screenH=$screenHeightPx calH=$calendarHeightPx isCollapsed=${viewModel.isCollapsed}") + } + Box( modifier = modifier .fillMaxSize() @@ -73,12 +79,11 @@ fun CalendarMonthView( } ) { Column(modifier = Modifier.padding(horizontal = 16.dp).onSizeChanged { size -> - calendarHeightPx = size.height - // 仅在首次展开时记录完整日历高度,折叠后不再覆盖 - if (!viewModel.isCollapsed && viewModel.collapseProgress < 0.01f) { - expandedCalendarHeightPx = size.height - } - }) { + // 仅在展开时记录日历总高度(折叠时 HorizontalPager 不缩小) + if (p < 0.01f) { + calendarHeightPx = size.height + } + }) { MonthHeader( year = currentYear, month = currentMonth, @@ -126,4 +131,4 @@ fun CalendarMonthView( ) } } -} +} \ No newline at end of file