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 <noreply@anthropic.com>
This commit is contained in:
parent
b95f748839
commit
fbb7904880
@ -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<DayData> {
|
||||
isCurrentMonth = date.monthNumber == month && date.year == year
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
},
|
||||
|
||||
@ -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
|
||||
)
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user