From 2a3089bf479ab59e5d772dae77afc25ca901d72b Mon Sep 17 00:00:00 2001 From: xfy Date: Thu, 9 Jul 2026 17:14:54 +0800 Subject: [PATCH] feat(shift): smooth height interpolation for mini calendar swipe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 滑动翻月时高度平滑过渡,不再跳变: - 复用主日历的 interpolatedWeeks 行数插值逻辑 (currentPageOffsetFraction 在当前页与目标页行数间 lerp) - 行高由 BoxWithConstraints 宽度推算(格宽=宽/7,aspectRatio(1f) 使行高=格宽) - HorizontalPager 套 Modifier.height(px).clipToBounds(),跟随手指实时变高 - 迷你月历简化版:无折叠动画,只保留展开态 gridHeightPx = rowH * weeks --- .../plus/rua/project/ui/ShiftCalendarGrid.kt | 59 ++++++++++++++----- 1 file changed, 45 insertions(+), 14 deletions(-) diff --git a/core/src/main/kotlin/plus/rua/project/ui/ShiftCalendarGrid.kt b/core/src/main/kotlin/plus/rua/project/ui/ShiftCalendarGrid.kt index 5751382..361b0b4 100644 --- a/core/src/main/kotlin/plus/rua/project/ui/ShiftCalendarGrid.kt +++ b/core/src/main/kotlin/plus/rua/project/ui/ShiftCalendarGrid.kt @@ -6,10 +6,12 @@ import androidx.compose.foundation.clickable import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.aspectRatio import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState @@ -38,6 +40,8 @@ import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clipToBounds +import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.style.TextAlign @@ -55,6 +59,7 @@ import kotlinx.datetime.number import kotlinx.datetime.plus import kotlinx.datetime.toLocalDateTime import kotlinx.datetime.todayIn +import kotlin.math.abs import kotlin.time.Clock import kotlin.time.Instant import plus.rua.project.RephaseFlip @@ -93,6 +98,7 @@ fun ShiftCalendarGrid( val viewMonth by remember { derivedStateOf { pageToYearMonth(pagerState.currentPage, initialYear, initialMonth).second } } + val density = LocalDensity.current Card( modifier = modifier.fillMaxWidth(), @@ -137,20 +143,45 @@ fun ShiftCalendarGrid( } } - // 滑动翻页区域:每页一个月的网格 - HorizontalPager( - state = pagerState, - beyondViewportPageCount = 0, - modifier = Modifier.fillMaxWidth() - ) { page -> - val (year, month) = pageToYearMonth(page, initialYear, initialMonth) - MonthGrid( - year = year, - month = month, - pattern = pattern, - onPatternChange = onPatternChange, - modifier = Modifier.fillMaxWidth() - ) + // 用 BoxWithConstraints 拿宽度,推算行高(格宽=宽/7,aspectRatio(1f) 使行高=格宽) + BoxWithConstraints(Modifier.fillMaxWidth()) { + val cellWidthPx = constraints.maxWidth / 7 + val rowHeightPx = cellWidthPx + + // 行数插值:滑动时在当前页与目标页行数间线性过渡,避免高度跳变 + val interpolatedWeeks by remember { + derivedStateOf { + val fraction = pagerState.currentPageOffsetFraction + if (abs(fraction) > OFFSET_FRACTION_THRESHOLD) { + val cp = pagerState.currentPage + val baseWeeks = calculateWeeksCountForPage(cp, today) + val targetPage = cp + if (fraction > 0) 1 else -1 + val targetWeeks = calculateWeeksCountForPage(targetPage, today) + lerp(baseWeeks.toFloat(), targetWeeks.toFloat(), abs(fraction)) + } else { + calculateWeeksCountForPage(pagerState.currentPage, today).toFloat() + } + } + } + val gridHeightPx = (rowHeightPx * interpolatedWeeks).toInt() + + HorizontalPager( + state = pagerState, + beyondViewportPageCount = 0, + modifier = Modifier + .fillMaxWidth() + .height(with(density) { gridHeightPx.toDp() }) + .clipToBounds() + ) { page -> + val (year, month) = pageToYearMonth(page, initialYear, initialMonth) + MonthGrid( + year = year, + month = month, + pattern = pattern, + onPatternChange = onPatternChange, + modifier = Modifier.fillMaxWidth() + ) + } } } }