Add debug logging and fix gridHeightPx derivedStateOf state tracking
gridHeightPx changed from derivedStateOf to direct computation because derivedStateOf cannot track non-State local variable changes, causing gridHeightPx to not update when rowHeightPx transitions from 0 to measured value. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
parent
ddc852a667
commit
c74de5f151
@ -47,12 +47,14 @@ class CalendarViewModel(private val coroutineScope: CoroutineScope) {
|
|||||||
val currentMonth: Int get() = selectedDate.month.number
|
val currentMonth: Int get() = selectedDate.month.number
|
||||||
|
|
||||||
fun selectDate(date: LocalDate) {
|
fun selectDate(date: LocalDate) {
|
||||||
|
println("CalendarViewModel: selectDate $date (was $selectedDate)")
|
||||||
selectedDate = date
|
selectedDate = date
|
||||||
}
|
}
|
||||||
|
|
||||||
fun onDrag(delta: Float) {
|
fun onDrag(delta: Float) {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
val new = (_collapseAnimatable.value + delta).coerceIn(0f, 1f)
|
val new = (_collapseAnimatable.value + delta).coerceIn(0f, 1f)
|
||||||
|
println("CalendarViewModel: onDrag delta=$delta, progress=${_collapseAnimatable.value} -> $new")
|
||||||
_collapseAnimatable.snapTo(new)
|
_collapseAnimatable.snapTo(new)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,17 +63,20 @@ class CalendarViewModel(private val coroutineScope: CoroutineScope) {
|
|||||||
fun onDragEnd() {
|
fun onDragEnd() {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
val current = _collapseAnimatable.value
|
val current = _collapseAnimatable.value
|
||||||
|
println("CalendarViewModel: onDragEnd current=$current, threshold=$COLLAPSE_THRESHOLD")
|
||||||
if (current > COLLAPSE_THRESHOLD) {
|
if (current > COLLAPSE_THRESHOLD) {
|
||||||
_collapseAnimatable.animateTo(
|
_collapseAnimatable.animateTo(
|
||||||
targetValue = 1f,
|
targetValue = 1f,
|
||||||
animationSpec = spring(dampingRatio = 0.8f, stiffness = 400f)
|
animationSpec = spring(dampingRatio = 0.8f, stiffness = 400f)
|
||||||
)
|
)
|
||||||
isCollapsed = true
|
isCollapsed = true
|
||||||
|
println("CalendarViewModel: collapsed=true")
|
||||||
} else {
|
} else {
|
||||||
_collapseAnimatable.animateTo(
|
_collapseAnimatable.animateTo(
|
||||||
targetValue = 0f,
|
targetValue = 0f,
|
||||||
animationSpec = spring(dampingRatio = 0.8f, stiffness = 400f)
|
animationSpec = spring(dampingRatio = 0.8f, stiffness = 400f)
|
||||||
)
|
)
|
||||||
|
println("CalendarViewModel: snapped back to 0f")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,6 +85,7 @@ class CalendarViewModel(private val coroutineScope: CoroutineScope) {
|
|||||||
fun onExpandDrag(delta: Float) {
|
fun onExpandDrag(delta: Float) {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
val new = (_collapseAnimatable.value + delta).coerceIn(0f, 1f)
|
val new = (_collapseAnimatable.value + delta).coerceIn(0f, 1f)
|
||||||
|
println("CalendarViewModel: onExpandDrag delta=$delta, progress=${_collapseAnimatable.value} -> $new")
|
||||||
_collapseAnimatable.snapTo(new)
|
_collapseAnimatable.snapTo(new)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -88,17 +94,20 @@ class CalendarViewModel(private val coroutineScope: CoroutineScope) {
|
|||||||
fun onExpandDragEnd() {
|
fun onExpandDragEnd() {
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
val current = _collapseAnimatable.value
|
val current = _collapseAnimatable.value
|
||||||
|
println("CalendarViewModel: onExpandDragEnd current=$current, threshold=$COLLAPSE_THRESHOLD")
|
||||||
if (current < COLLAPSE_THRESHOLD) {
|
if (current < COLLAPSE_THRESHOLD) {
|
||||||
_collapseAnimatable.animateTo(
|
_collapseAnimatable.animateTo(
|
||||||
targetValue = 0f,
|
targetValue = 0f,
|
||||||
animationSpec = spring(dampingRatio = 0.8f, stiffness = 400f)
|
animationSpec = spring(dampingRatio = 0.8f, stiffness = 400f)
|
||||||
)
|
)
|
||||||
isCollapsed = false
|
isCollapsed = false
|
||||||
|
println("CalendarViewModel: expanded=false")
|
||||||
} else {
|
} else {
|
||||||
_collapseAnimatable.animateTo(
|
_collapseAnimatable.animateTo(
|
||||||
targetValue = 1f,
|
targetValue = 1f,
|
||||||
animationSpec = spring(dampingRatio = 0.8f, stiffness = 400f)
|
animationSpec = spring(dampingRatio = 0.8f, stiffness = 400f)
|
||||||
)
|
)
|
||||||
|
println("CalendarViewModel: snapped back to 1f")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,6 +33,7 @@ fun BottomCard(
|
|||||||
) {
|
) {
|
||||||
val density = LocalDensity.current
|
val density = LocalDensity.current
|
||||||
val dragRange = with(density) { DRAG_RANGE_DP.dp.toPx() }
|
val dragRange = with(density) { DRAG_RANGE_DP.dp.toPx() }
|
||||||
|
println("BottomCard: isCollapsed=${viewModel.isCollapsed}, dragRange=$dragRange, progress=${viewModel.collapseProgress}")
|
||||||
|
|
||||||
Surface(
|
Surface(
|
||||||
modifier = modifier
|
modifier = modifier
|
||||||
|
|||||||
@ -115,7 +115,10 @@ fun CalendarMonthPage(
|
|||||||
.then(
|
.then(
|
||||||
if (weekIndex == 0 && rowHeightPx == 0) {
|
if (weekIndex == 0 && rowHeightPx == 0) {
|
||||||
Modifier.onSizeChanged { size ->
|
Modifier.onSizeChanged { size ->
|
||||||
if (size.height > 0) onRowHeightMeasured?.invoke(size.height)
|
if (size.height > 0) {
|
||||||
|
println("CalendarMonthPage: measured rowHeight=${size.height}px, reporting to parent")
|
||||||
|
onRowHeightMeasured?.invoke(size.height)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else Modifier
|
} else Modifier
|
||||||
)
|
)
|
||||||
|
|||||||
@ -31,6 +31,8 @@ import kotlin.math.abs
|
|||||||
import kotlin.time.Clock
|
import kotlin.time.Clock
|
||||||
import plus.rua.project.CalendarViewModel
|
import plus.rua.project.CalendarViewModel
|
||||||
|
|
||||||
|
private const val TAG = "CalendarMonthView"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 日历主界面,包含月/周视图切换和折叠动画。
|
* 日历主界面,包含月/周视图切换和折叠动画。
|
||||||
*
|
*
|
||||||
@ -59,8 +61,10 @@ 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 p = viewModel.collapseProgress
|
||||||
|
println("$TAG: collapseProgress=$p, isCollapsed=${viewModel.isCollapsed}")
|
||||||
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()
|
||||||
|
println("$TAG: headerHeightPx=$headerHeightPx (month=$monthHeaderHeightPx, weekday=$weekdayHeaderHeightPx), rowPaddingPx=$rowPaddingPx")
|
||||||
|
|
||||||
val interpolatedWeeks by remember {
|
val interpolatedWeeks by remember {
|
||||||
derivedStateOf {
|
derivedStateOf {
|
||||||
@ -85,27 +89,28 @@ fun CalendarMonthView(
|
|||||||
(cellWidth + rowPadding).toInt()
|
(cellWidth + rowPadding).toInt()
|
||||||
} else 0
|
} else 0
|
||||||
|
|
||||||
|
println("$TAG: screenWidthPx=$screenWidthPx, screenHeightPx=$screenHeightPx, estimatedRowHeightPx=$estimatedRowHeightPx, measuredRowHeightPx=$rowHeightPx")
|
||||||
|
|
||||||
val effectiveRowHeightPx = if (rowHeightPx > 0) rowHeightPx else estimatedRowHeightPx
|
val effectiveRowHeightPx = if (rowHeightPx > 0) rowHeightPx else estimatedRowHeightPx
|
||||||
|
|
||||||
// 折叠时网格高度公式(与 CalendarMonthPage 一致):
|
// 折叠时网格高度公式(与 CalendarMonthPage 一致):
|
||||||
// gridH = rowH × (1 + (weeks-1) × (1-p))
|
// gridH = rowH × (1 + (weeks-1) × (1-p))
|
||||||
val effectiveWeeks = interpolatedWeeks
|
val effectiveWeeks = interpolatedWeeks
|
||||||
|
|
||||||
val gridHeightPx by remember {
|
// gridHeightPx 必须直接计算而非 derivedStateOf,因为 effectiveRowHeightPx 依赖 rowHeightPx state,
|
||||||
derivedStateOf {
|
// derivedStateOf 无法追踪非 State 的局部变量变化,导致 rowHeightPx 从 0 变为测量值时 gridHeightPx 不更新
|
||||||
if (effectiveRowHeightPx > 0) {
|
val gridHeightPx = if (effectiveRowHeightPx > 0) {
|
||||||
val rowH = effectiveRowHeightPx.toFloat()
|
val rowH = effectiveRowHeightPx.toFloat()
|
||||||
if (p > OFFSET_FRACTION_THRESHOLD) {
|
if (p > OFFSET_FRACTION_THRESHOLD) {
|
||||||
(rowH * (1 + (effectiveWeeks - 1) * (1f - p))).toInt()
|
(rowH * (1 + (effectiveWeeks - 1) * (1f - p))).toInt()
|
||||||
} else {
|
} else {
|
||||||
(rowH * effectiveWeeks).toInt()
|
(rowH * effectiveWeeks).toInt()
|
||||||
}
|
|
||||||
} else 0
|
|
||||||
}
|
}
|
||||||
}
|
} else 0
|
||||||
|
|
||||||
val calendarAreaHeightPx = headerHeightPx + gridHeightPx + rowPaddingPx
|
val calendarAreaHeightPx = headerHeightPx + gridHeightPx + rowPaddingPx
|
||||||
val cardHeightPx = if (screenHeightPx > 0 && calendarAreaHeightPx > 0) screenHeightPx - calendarAreaHeightPx else 0
|
val cardHeightPx = if (screenHeightPx > 0 && calendarAreaHeightPx > 0) screenHeightPx - calendarAreaHeightPx else 0
|
||||||
|
println("$TAG: effectiveRowHeightPx=$effectiveRowHeightPx, effectiveWeeks=$effectiveWeeks, gridHeightPx=$gridHeightPx, calendarAreaHeightPx=$calendarAreaHeightPx, cardHeightPx=$cardHeightPx")
|
||||||
|
|
||||||
// 当 rowHeightPx 已知时,用计算的高度约束 pager;否则让 pager 自由扩展以测量行高
|
// 当 rowHeightPx 已知时,用计算的高度约束 pager;否则让 pager 自由扩展以测量行高
|
||||||
val pagerModifier = if (rowHeightPx > 0 && gridHeightPx > 0) {
|
val pagerModifier = if (rowHeightPx > 0 && gridHeightPx > 0) {
|
||||||
@ -141,6 +146,7 @@ fun CalendarMonthView(
|
|||||||
)
|
)
|
||||||
// 完全折叠且无动画时显示 WeekPager,否则显示 CalendarPager(含下拉恢复过程)
|
// 完全折叠且无动画时显示 WeekPager,否则显示 CalendarPager(含下拉恢复过程)
|
||||||
if (viewModel.isCollapsed && viewModel.collapseProgress >= 1f) {
|
if (viewModel.isCollapsed && viewModel.collapseProgress >= 1f) {
|
||||||
|
println("$TAG: Showing WeekPager (isCollapsed=true, progress=${viewModel.collapseProgress})")
|
||||||
WeekPager(
|
WeekPager(
|
||||||
selectedDate = viewModel.selectedDate,
|
selectedDate = viewModel.selectedDate,
|
||||||
today = today,
|
today = today,
|
||||||
@ -152,6 +158,7 @@ fun CalendarMonthView(
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
|
println("$TAG: Showing CalendarPager (isCollapsed=${viewModel.isCollapsed}, progress=${viewModel.collapseProgress})")
|
||||||
CalendarPager(
|
CalendarPager(
|
||||||
selectedDate = viewModel.selectedDate,
|
selectedDate = viewModel.selectedDate,
|
||||||
today = today,
|
today = today,
|
||||||
@ -174,6 +181,7 @@ fun CalendarMonthView(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cardHeightPx > 0) {
|
if (cardHeightPx > 0) {
|
||||||
|
println("$TAG: BottomCard height=${with(density) { cardHeightPx.toDp() }}")
|
||||||
BottomCard(
|
BottomCard(
|
||||||
viewModel = viewModel,
|
viewModel = viewModel,
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user