Fix row height measurement order and increase row padding
Move padding after onSizeChanged in CalendarMonthPage so row height measurement excludes padding. Rename p→collapseProgress for clarity. Add comments explaining grid height calculation and pager switching. Increase ROW_PADDING_DP from 4 to 6. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
85fe11d9f1
commit
c751b56297
@ -111,7 +111,6 @@ fun CalendarMonthPage(
|
|||||||
else Modifier
|
else Modifier
|
||||||
)
|
)
|
||||||
.offset(y = yOffsetDp)
|
.offset(y = yOffsetDp)
|
||||||
.padding(vertical = ROW_PADDING_DP.dp)
|
|
||||||
.then(
|
.then(
|
||||||
if (weekIndex == 0 && rowHeightPx == 0) {
|
if (weekIndex == 0 && rowHeightPx == 0) {
|
||||||
Modifier.onSizeChanged { size ->
|
Modifier.onSizeChanged { size ->
|
||||||
@ -121,6 +120,7 @@ fun CalendarMonthPage(
|
|||||||
}
|
}
|
||||||
} else Modifier
|
} else Modifier
|
||||||
)
|
)
|
||||||
|
.padding(vertical = ROW_PADDING_DP.dp)
|
||||||
) {
|
) {
|
||||||
week.forEach { dayData ->
|
week.forEach { dayData ->
|
||||||
DayCell(
|
DayCell(
|
||||||
|
|||||||
@ -58,11 +58,12 @@ fun CalendarMonthView(
|
|||||||
|
|
||||||
val pagerState = rememberPagerState(initialPage = START_PAGE, pageCount = { Int.MAX_VALUE })
|
val pagerState = rememberPagerState(initialPage = START_PAGE, pageCount = { Int.MAX_VALUE })
|
||||||
|
|
||||||
val p = viewModel.collapseProgress
|
val collapseProgress = viewModel.collapseProgress
|
||||||
val headerHeightPx = monthHeaderHeightPx + weekdayHeaderHeightPx
|
val headerHeightPx = monthHeaderHeightPx + weekdayHeaderHeightPx
|
||||||
val rowPaddingPx = with(density) { ROW_PADDING_DP.dp.toPx() }.toInt()
|
val rowPaddingPx = with(density) { ROW_PADDING_DP.dp.toPx() }.toInt()
|
||||||
val cardGapPx = with(density) { lerp(CARD_GAP_EXPANDED_DP.toFloat(), CARD_GAP_COLLAPSED_DP.toFloat(), p).dp.toPx() }.toInt()
|
val cardGapPx = with(density) { lerp(CARD_GAP_EXPANDED_DP.toFloat(), CARD_GAP_COLLAPSED_DP.toFloat(), collapseProgress).dp.toPx() }.toInt()
|
||||||
|
|
||||||
|
// 翻页时在相邻月份行数之间插值,使 BottomCard 高度平滑过渡
|
||||||
val interpolatedWeeks by remember {
|
val interpolatedWeeks by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
val fraction = pagerState.currentPageOffsetFraction
|
val fraction = pagerState.currentPageOffsetFraction
|
||||||
@ -80,6 +81,7 @@ fun CalendarMonthView(
|
|||||||
|
|
||||||
// 预估行高:DayCell aspectRatio=1,宽度 = (screenWidth - horizontalPadding) / 7
|
// 预估行高:DayCell aspectRatio=1,宽度 = (screenWidth - horizontalPadding) / 7
|
||||||
// 加上 Row 的 vertical padding (4dp × 2)
|
// 加上 Row 的 vertical padding (4dp × 2)
|
||||||
|
// 用于 rowHeightPx 尚未测量时的 fallback,避免首次布局高度为 0
|
||||||
val estimatedRowHeightPx = if (screenWidthPx > 0) {
|
val estimatedRowHeightPx = if (screenWidthPx > 0) {
|
||||||
val cellWidth = (screenWidthPx - with(density) { (HORIZONTAL_PADDING_DP * 2).dp.toPx() }) / 7
|
val cellWidth = (screenWidthPx - with(density) { (HORIZONTAL_PADDING_DP * 2).dp.toPx() }) / 7
|
||||||
val rowPadding = with(density) { (ROW_PADDING_DP * 2).dp.toPx() }
|
val rowPadding = with(density) { (ROW_PADDING_DP * 2).dp.toPx() }
|
||||||
@ -88,25 +90,27 @@ fun CalendarMonthView(
|
|||||||
|
|
||||||
val effectiveRowHeightPx = if (rowHeightPx > 0) rowHeightPx else estimatedRowHeightPx
|
val effectiveRowHeightPx = if (rowHeightPx > 0) rowHeightPx else estimatedRowHeightPx
|
||||||
|
|
||||||
// 折叠时网格高度公式(与 CalendarMonthPage 一致):
|
|
||||||
// gridH = rowH × (1 + (weeks-1) × (1-p))
|
|
||||||
val effectiveWeeks = interpolatedWeeks
|
val effectiveWeeks = interpolatedWeeks
|
||||||
|
|
||||||
// gridHeightPx 必须直接计算而非 derivedStateOf,因为 effectiveRowHeightPx 依赖 rowHeightPx state,
|
// 折叠时网格高度公式(与 CalendarMonthPage 一致):
|
||||||
// derivedStateOf 无法追踪非 State 的局部变量变化,导致 rowHeightPx 从 0 变为测量值时 gridHeightPx 不更新
|
// collapseProgress=0 展开时 gridH = rowH × weeks;collapseProgress=1 折叠时 gridH = rowH × 1
|
||||||
|
// 中间态:gridH = rowH × (1 + (weeks-1) × (1-collapseProgress))
|
||||||
|
// 必须直接计算而非 derivedStateOf:effectiveRowHeightPx 依赖 rowHeightPx state,
|
||||||
|
// derivedStateOf 无法追踪非 State 局部变量变化,导致 rowHeightPx 从 0 变为测量值时 gridHeightPx 不更新
|
||||||
val gridHeightPx = if (effectiveRowHeightPx > 0) {
|
val gridHeightPx = if (effectiveRowHeightPx > 0) {
|
||||||
val rowH = effectiveRowHeightPx.toFloat()
|
val rowH = effectiveRowHeightPx.toFloat()
|
||||||
if (p > OFFSET_FRACTION_THRESHOLD) {
|
if (collapseProgress > OFFSET_FRACTION_THRESHOLD) {
|
||||||
(rowH * (1 + (effectiveWeeks - 1) * (1f - p))).toInt()
|
(rowH * (1 + (effectiveWeeks - 1) * (1f - collapseProgress))).toInt()
|
||||||
} else {
|
} else {
|
||||||
(rowH * effectiveWeeks).toInt()
|
(rowH * effectiveWeeks).toInt()
|
||||||
}
|
}
|
||||||
} else 0
|
} else 0
|
||||||
|
|
||||||
|
// BottomCard 高度 = 屏幕剩余空间(屏幕高度 - 日历区域高度)
|
||||||
val calendarAreaHeightPx = headerHeightPx + gridHeightPx + rowPaddingPx + cardGapPx
|
val calendarAreaHeightPx = headerHeightPx + gridHeightPx + rowPaddingPx + cardGapPx
|
||||||
val cardHeightPx = if (screenHeightPx > 0 && calendarAreaHeightPx > 0) screenHeightPx - calendarAreaHeightPx else 0
|
val cardHeightPx = if (screenHeightPx > 0 && calendarAreaHeightPx > 0) screenHeightPx - calendarAreaHeightPx else 0
|
||||||
|
|
||||||
// 当 rowHeightPx 已知时,用计算的高度约束 pager;否则让 pager 自由扩展以测量行高
|
// 行高已知时约束 pager 高度,防止内容溢出;否则让 pager 自由扩展以触发首次行高测量
|
||||||
val pagerModifier = if (rowHeightPx > 0 && gridHeightPx > 0) {
|
val pagerModifier = if (rowHeightPx > 0 && gridHeightPx > 0) {
|
||||||
Modifier
|
Modifier
|
||||||
.height(with(density) { gridHeightPx.toDp() })
|
.height(with(density) { gridHeightPx.toDp() })
|
||||||
@ -138,13 +142,15 @@ fun CalendarMonthView(
|
|||||||
weekdayHeaderHeightPx = size.height
|
weekdayHeaderHeightPx = size.height
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
// 完全折叠且无动画时显示 WeekPager,否则显示 CalendarPager(含下拉恢复过程)
|
// 完全折叠且无动画时切换到 WeekPager(单行高效渲染),
|
||||||
|
// 否则使用 CalendarPager(含折叠动画和下拉恢复过程)
|
||||||
if (viewModel.isCollapsed && viewModel.collapseProgress >= 1f) {
|
if (viewModel.isCollapsed && viewModel.collapseProgress >= 1f) {
|
||||||
WeekPager(
|
WeekPager(
|
||||||
selectedDate = viewModel.selectedDate,
|
selectedDate = viewModel.selectedDate,
|
||||||
today = today,
|
today = today,
|
||||||
onDateClick = { date -> viewModel.selectDate(date) },
|
onDateClick = { date -> viewModel.selectDate(date) },
|
||||||
onWeekChanged = { weekMonday ->
|
onWeekChanged = { weekMonday ->
|
||||||
|
// 优先选中当周内的今天,否则选中该周周一
|
||||||
val weekSunday = weekMonday.plus(DatePeriod(days = 6))
|
val weekSunday = weekMonday.plus(DatePeriod(days = 6))
|
||||||
val date = if (today in weekMonday..weekSunday) today else weekMonday
|
val date = if (today in weekMonday..weekSunday) today else weekMonday
|
||||||
viewModel.selectDate(date)
|
viewModel.selectDate(date)
|
||||||
@ -157,6 +163,7 @@ fun CalendarMonthView(
|
|||||||
today = today,
|
today = today,
|
||||||
onDateClick = { date -> viewModel.selectDate(date) },
|
onDateClick = { date -> viewModel.selectDate(date) },
|
||||||
onMonthChanged = { year, month ->
|
onMonthChanged = { year, month ->
|
||||||
|
// 优先选中当月内的今天,否则选中该月1号
|
||||||
val date = if (year == today.year && today.month.number == month) today
|
val date = if (year == today.year && today.month.number == month) today
|
||||||
else LocalDate(year, month, 1)
|
else LocalDate(year, month, 1)
|
||||||
viewModel.selectDate(date)
|
viewModel.selectDate(date)
|
||||||
@ -183,4 +190,4 @@ fun CalendarMonthView(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,7 +16,7 @@ const val COLLAPSE_THRESHOLD = 0.5f
|
|||||||
const val OFFSET_FRACTION_THRESHOLD = 0.01f
|
const val OFFSET_FRACTION_THRESHOLD = 0.01f
|
||||||
|
|
||||||
/** 行内 vertical padding (dp) */
|
/** 行内 vertical padding (dp) */
|
||||||
const val ROW_PADDING_DP = 4
|
const val ROW_PADDING_DP = 6
|
||||||
|
|
||||||
/** 日历网格水平 padding (dp) */
|
/** 日历网格水平 padding (dp) */
|
||||||
const val HORIZONTAL_PADDING_DP = 16
|
const val HORIZONTAL_PADDING_DP = 16
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user