From fbb79048807e5dbc7d21f4057e64ac826673711d Mon Sep 17 00:00:00 2001 From: xfy Date: Fri, 15 May 2026 02:03:21 +0800 Subject: [PATCH] Unify height calculation with effectiveWeeks and fix swipe interpolation continuity Pass effectiveWeeks from CalendarMonthView through CalendarPager to CalendarMonthPage so both use the same formula H*(1+(weeks-1)*(1-p)). Fix interpolatedWeeks to anchor on settledPage instead of currentPage, preventing direction/fraction discontinuity when currentPage jumps during swipe transitions. Co-Authored-By: Claude Opus 4.7 --- .../plus/rua/project/ui/CalendarMonthPage.kt | 21 ++++++++------- .../plus/rua/project/ui/CalendarMonthView.kt | 27 +++++++++++++++---- .../plus/rua/project/ui/CalendarPager.kt | 2 ++ 3 files changed, 35 insertions(+), 15 deletions(-) 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 28b664c..1b58061 100644 --- a/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarMonthPage.kt +++ b/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarMonthPage.kt @@ -19,6 +19,8 @@ import kotlinx.datetime.LocalDate import kotlinx.datetime.minus import kotlinx.datetime.plus +private const val TAG = "CalMonthPage" + /** * 月度日历网格页面,支持折叠动画。 * @@ -36,6 +38,7 @@ fun CalendarMonthPage( onDateClick: (LocalDate) -> Unit, collapseProgress: Float, rowHeightPx: Int, + effectiveWeeks: Float, onRowHeightMeasured: ((Int) -> Unit)? = null, modifier: Modifier = Modifier ) { @@ -52,17 +55,15 @@ fun CalendarMonthPage( val hasSelectedWeek = selectedWeekIndex >= 0 val H = rowHeightPx.toFloat() - // 总高度 = 选中行高度 + 上方行压缩高度 + 下方行压缩高度 + // 使用与 CalendarMonthView 一致的 effectiveWeeks 计算高度,避免滑动中高度不匹配 val totalHeightDp = if (rowHeightPx > 0) { - 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() } - } + val p = collapseProgress + val totalPx = H * (1 + (effectiveWeeks - 1) * (1f - p)) + println("[$TAG] year=$year month=$month rowH=$rowHeightPx H=$H effWeeks=$effectiveWeeks " + + "weeks.size=${weeks.size} p=$p totalPx=$totalPx selWeek=$selectedWeekIndex") + with(density) { totalPx.toDp() } } else { + println("[$TAG] year=$year month=$month rowH=0 (not yet measured)") null } @@ -161,4 +162,4 @@ private fun generateMonthDays(year: Int, month: Int): List { isCurrentMonth = date.monthNumber == month && date.year == year ) } -} \ No newline at end of file +} 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 293a740..4b0ef33 100644 --- a/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarMonthView.kt +++ b/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarMonthView.kt @@ -32,6 +32,7 @@ import plus.rua.project.CalendarViewModel private const val START_PAGE = Int.MAX_VALUE / 2 private const val ROW_PADDING_DP = 4 +private const val TAG = "CalMonthView" /** * 日历主界面,包含月/周视图切换和折叠动画。 @@ -67,11 +68,19 @@ fun CalendarMonthView( val rowPaddingPx = with(density) { ROW_PADDING_DP.dp.toPx() }.toInt() // 滑动偏移插值行数 + // 始终以 settledPage 为锚点,currentPage - settledPage 确定方向(-1/0/+1), + // abs(offsetFraction) 为过渡进度。 + // 这样在 currentPage 跳变前后,方向和进度都是连续的: + // 跳变前: sp=8月, cp=8月, diff=0, offsetFraction>0 → 目标9月, fraction 0→0.5 + // 跳变后: sp=8月, cp=9月, diff=+1 → 目标9月, fraction 0.5→0 val offsetFraction by remember { derivedStateOf { pagerState.currentPageOffsetFraction } } val interpolatedWeeks = if (abs(offsetFraction) > 0.01f) { - val targetPage = if (offsetFraction > 0) pagerState.currentPage + 1 else pagerState.currentPage - 1 + val sp = pagerState.settledPage + val diff = pagerState.currentPage - sp // -1, 0, or +1 + val targetPage = if (diff != 0) sp + diff else sp + if (offsetFraction > 0) 1 else -1 + val baseWeeks = calculateWeeksCountForPage(sp, today) val targetWeeks = calculateWeeksCountForPage(targetPage, today) - lerp(currentWeeksCount.toFloat(), targetWeeks.toFloat(), abs(offsetFraction)) + lerp(baseWeeks.toFloat(), targetWeeks.toFloat(), abs(offsetFraction)) } else { currentWeeksCount.toFloat() } @@ -88,19 +97,26 @@ fun CalendarMonthView( // 折叠时网格高度公式(与 CalendarMonthPage 一致): // gridH = rowH × (1 + (weeks-1) × (1-p)) + val effectiveWeeks = interpolatedWeeks + val gridHeightPx = if (effectiveRowHeightPx > 0) { val rowH = effectiveRowHeightPx.toFloat() - val weeks = interpolatedWeeks if (p > 0.01f) { - (rowH * (1 + (weeks - 1) * (1f - p))).toInt() + (rowH * (1 + (effectiveWeeks - 1) * (1f - p))).toInt() } else { - (rowH * weeks).toInt() + (rowH * effectiveWeeks).toInt() } } else 0 val calendarAreaHeightPx = headerHeightPx + gridHeightPx + rowPaddingPx val cardHeightPx = if (screenHeightPx > 0 && calendarAreaHeightPx > 0) screenHeightPx - calendarAreaHeightPx else 0 + println("[$TAG] p=$p rowH=$rowHeightPx estRowH=$estimatedRowHeightPx effRowH=$effectiveRowHeightPx " + + "headerH=$headerHeightPx gridH=$gridHeightPx calAreaH=$calendarAreaHeightPx " + + "screenH=$screenHeightPx cardH=$cardHeightPx " + + "currentWeeks=$currentWeeksCount interpolatedWeeks=$interpolatedWeeks effectiveWeeks=$effectiveWeeks " + + "offsetFraction=$offsetFraction currentPage=${pagerState.currentPage} settledPage=${pagerState.settledPage}") + // 当 rowHeightPx 已知时,用计算的高度约束 pager;否则让 pager 自由扩展以测量行高 val pagerModifier = if (rowHeightPx > 0 && gridHeightPx > 0) { Modifier @@ -162,6 +178,7 @@ fun CalendarMonthView( }, collapseProgress = viewModel.collapseProgress, rowHeightPx = rowHeightPx, + effectiveWeeks = effectiveWeeks, onWeeksChanged = { weeks -> currentWeeksCount = weeks }, 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 a14619f..c176561 100644 --- a/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarPager.kt +++ b/shared/src/commonMain/kotlin/plus/rua/project/ui/CalendarPager.kt @@ -38,6 +38,7 @@ fun CalendarPager( onMonthChanged: (year: Int, month: Int) -> Unit, collapseProgress: Float, rowHeightPx: Int, + effectiveWeeks: Float, onWeeksChanged: ((Int) -> Unit)? = null, onRowHeightMeasured: ((Int) -> Unit)? = null, pagerState: PagerState, @@ -82,6 +83,7 @@ fun CalendarPager( }, collapseProgress = collapseProgress, rowHeightPx = rowHeightPx, + effectiveWeeks = effectiveWeeks, onRowHeightMeasured = onRowHeightMeasured ) }