feat: 使用 AnimatedContent 平滑切换 CalendarPager ↔ WeekPager
- 用 AnimatedContent 包装 pager 切换,添加 fadeIn/fadeOut 过渡 - 延迟 50ms 切换避免折叠 spring 动画期间的视觉跳跃 - 修复 WeekRow 下方行的 yOffset 计算(移除 phase2 项) - WeekPager 添加农历缓存支持 - 添加折叠动画调试日志 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
4c53f234cf
commit
2592a5fa55
@ -20,8 +20,11 @@ import kotlinx.datetime.plus
|
|||||||
import kotlinx.datetime.todayIn
|
import kotlinx.datetime.todayIn
|
||||||
import plus.rua.project.ui.COLLAPSE_THRESHOLD
|
import plus.rua.project.ui.COLLAPSE_THRESHOLD
|
||||||
import plus.rua.project.ui.getMonthGridInfo
|
import plus.rua.project.ui.getMonthGridInfo
|
||||||
|
import android.util.Log
|
||||||
import kotlin.time.Clock
|
import kotlin.time.Clock
|
||||||
|
|
||||||
|
private const val TAG_VM = "CalendarExpand"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 日历日期数据,用于网格单元格渲染。
|
* 日历日期数据,用于网格单元格渲染。
|
||||||
*
|
*
|
||||||
@ -285,7 +288,9 @@ class CalendarViewModel(
|
|||||||
* @param delta 拖拽增量,已归一化到 [0,1] 区间
|
* @param delta 拖拽增量,已归一化到 [0,1] 区间
|
||||||
*/
|
*/
|
||||||
fun onExpandDrag(delta: Float) {
|
fun onExpandDrag(delta: Float) {
|
||||||
|
val old = _collapseProgress.value
|
||||||
_collapseProgress.value = (_collapseProgress.value + delta).coerceIn(0f, 1f)
|
_collapseProgress.value = (_collapseProgress.value + delta).coerceIn(0f, 1f)
|
||||||
|
Log.d(TAG_VM, "onExpandDrag: delta=$delta old=$old new=${_collapseProgress.value}")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -295,13 +300,16 @@ class CalendarViewModel(
|
|||||||
*/
|
*/
|
||||||
fun onExpandDragEnd() {
|
fun onExpandDragEnd() {
|
||||||
val progress = _collapseProgress.value
|
val progress = _collapseProgress.value
|
||||||
if (progress < (1 - COLLAPSE_THRESHOLD)) {
|
val result = if (progress < (1 - COLLAPSE_THRESHOLD)) {
|
||||||
_isCollapsed.value = false
|
_isCollapsed.value = false
|
||||||
_collapseProgress.value = 0f
|
_collapseProgress.value = 0f
|
||||||
|
"EXPANDED"
|
||||||
} else {
|
} else {
|
||||||
_isCollapsed.value = true
|
_isCollapsed.value = true
|
||||||
_collapseProgress.value = 1f
|
_collapseProgress.value = 1f
|
||||||
|
"COLLAPSED (bounce back)"
|
||||||
}
|
}
|
||||||
|
Log.d(TAG_VM, "onExpandDragEnd: progress=$progress threshold=${1 - COLLAPSE_THRESHOLD} result=$result")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -21,6 +21,7 @@ import androidx.compose.ui.layout.onSizeChanged
|
|||||||
import androidx.compose.ui.platform.LocalDensity
|
import androidx.compose.ui.platform.LocalDensity
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.zIndex
|
import androidx.compose.ui.zIndex
|
||||||
|
import android.util.Log
|
||||||
import kotlinx.datetime.DatePeriod
|
import kotlinx.datetime.DatePeriod
|
||||||
import kotlinx.datetime.LocalDate
|
import kotlinx.datetime.LocalDate
|
||||||
import kotlinx.datetime.minus
|
import kotlinx.datetime.minus
|
||||||
@ -30,6 +31,8 @@ import plus.rua.project.DayCellInfo
|
|||||||
import plus.rua.project.LunarCache
|
import plus.rua.project.LunarCache
|
||||||
import plus.rua.project.ShiftKind
|
import plus.rua.project.ShiftKind
|
||||||
|
|
||||||
|
private const val TAG_CMP = "CalendarExpandAnim"
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 月度日历网格页面,支持两阶段折叠动画。
|
* 月度日历网格页面,支持两阶段折叠动画。
|
||||||
@ -185,7 +188,7 @@ private fun WeekRow(
|
|||||||
!hasAnchor -> weekIndex * h - collapseProgress * weeksSize * h
|
!hasAnchor -> weekIndex * h - collapseProgress * weeksSize * h
|
||||||
isAnchor -> anchorIndex * h * (1f - phase1)
|
isAnchor -> anchorIndex * h * (1f - phase1)
|
||||||
isAbove -> weekIndex * h - phase1 * anchorIndex * h
|
isAbove -> weekIndex * h - phase1 * anchorIndex * h
|
||||||
isBelow -> weekIndex * h - phase1 * anchorIndex * h - phase2 * belowRowsHeight
|
isBelow -> weekIndex * h - phase1 * anchorIndex * h
|
||||||
else -> weekIndex * h
|
else -> weekIndex * h
|
||||||
}
|
}
|
||||||
} else 0f
|
} else 0f
|
||||||
@ -198,6 +201,10 @@ private fun WeekRow(
|
|||||||
else -> 1f
|
else -> 1f
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isAnchor || isBelow) {
|
||||||
|
Log.d(TAG_CMP, "WeekRow[$weekIndex]: isAnchor=$isAnchor isAbove=$isAbove isBelow=$isBelow phase1=$phase1 phase2=$phase2 yOffsetPx=$yOffsetPx rowAlpha=$rowAlpha collapseProgress=$collapseProgress")
|
||||||
|
}
|
||||||
|
|
||||||
if (rowAlpha > 0.01f) {
|
if (rowAlpha > 0.01f) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier
|
modifier = Modifier
|
||||||
|
|||||||
@ -520,20 +520,66 @@ private fun CalendarPagerArea(
|
|||||||
modifier
|
modifier
|
||||||
}
|
}
|
||||||
|
|
||||||
CalendarPager(
|
// 延迟切换:等折叠 spring 动画完全稳定后再切到 WeekPager,避免视觉跳跃
|
||||||
selectedDate = selectedDate,
|
var showWeekPager by remember { mutableStateOf(false) }
|
||||||
today = today,
|
|
||||||
onDateClick = onDateClick,
|
LaunchedEffect(isCollapsed, collapseProgress) {
|
||||||
onMonthChanged = onMonthChanged,
|
if (isCollapsed && collapseProgress >= 0.999f) {
|
||||||
collapseProgress = collapseProgress,
|
delay(50)
|
||||||
rowHeightPx = rowHeightPx,
|
showWeekPager = true
|
||||||
effectiveWeeks = effectiveWeeks,
|
} else if (!isCollapsed) {
|
||||||
shiftKindAt = shiftKindAt,
|
showWeekPager = false
|
||||||
showLegalHoliday = showLegalHoliday,
|
}
|
||||||
onRowHeightMeasured = onRowHeightMeasured,
|
}
|
||||||
pagerState = pagerState,
|
|
||||||
|
AnimatedContent(
|
||||||
|
targetState = showWeekPager,
|
||||||
|
transitionSpec = { fadeIn(tween(80)) togetherWith fadeOut(tween(80)) },
|
||||||
|
label = "pager_switch",
|
||||||
modifier = pagerModifier
|
modifier = pagerModifier
|
||||||
)
|
) { useWeekPager ->
|
||||||
|
if (useWeekPager) {
|
||||||
|
WeekPager(
|
||||||
|
selectedDate = selectedDate,
|
||||||
|
today = today,
|
||||||
|
onDateClick = onDateClick,
|
||||||
|
onWeekChanged = { weekMonday ->
|
||||||
|
val weekSunday = weekMonday.plus(DatePeriod(days = 6))
|
||||||
|
val date = when {
|
||||||
|
today in weekMonday..weekSunday -> today
|
||||||
|
weekMonday.month != weekSunday.month -> {
|
||||||
|
if (weekMonday < selectedDate) {
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
|
LocalDate(weekSunday.year, weekSunday.month.number, 1)
|
||||||
|
} else {
|
||||||
|
weekMonday
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> weekMonday
|
||||||
|
}
|
||||||
|
onDateClick(date)
|
||||||
|
},
|
||||||
|
shiftKindAt = shiftKindAt,
|
||||||
|
showLegalHoliday = showLegalHoliday,
|
||||||
|
modifier = Modifier
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
CalendarPager(
|
||||||
|
selectedDate = selectedDate,
|
||||||
|
today = today,
|
||||||
|
onDateClick = onDateClick,
|
||||||
|
onMonthChanged = onMonthChanged,
|
||||||
|
collapseProgress = collapseProgress,
|
||||||
|
rowHeightPx = rowHeightPx,
|
||||||
|
effectiveWeeks = effectiveWeeks,
|
||||||
|
shiftKindAt = shiftKindAt,
|
||||||
|
showLegalHoliday = showLegalHoliday,
|
||||||
|
onRowHeightMeasured = onRowHeightMeasured,
|
||||||
|
pagerState = pagerState,
|
||||||
|
modifier = Modifier
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|||||||
@ -18,10 +18,13 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.alpha
|
import androidx.compose.ui.draw.alpha
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import kotlinx.coroutines.flow.drop
|
import kotlinx.coroutines.flow.drop
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
import kotlinx.datetime.DatePeriod
|
import kotlinx.datetime.DatePeriod
|
||||||
import kotlinx.datetime.LocalDate
|
import kotlinx.datetime.LocalDate
|
||||||
import kotlinx.datetime.daysUntil
|
import kotlinx.datetime.daysUntil
|
||||||
import kotlinx.datetime.plus
|
import kotlinx.datetime.plus
|
||||||
|
import plus.rua.project.DayCellInfo
|
||||||
|
import plus.rua.project.LunarCache
|
||||||
import plus.rua.project.ShiftKind
|
import plus.rua.project.ShiftKind
|
||||||
import plus.rua.project.composeTraceBeginSection
|
import plus.rua.project.composeTraceBeginSection
|
||||||
import plus.rua.project.composeTraceEndSection
|
import plus.rua.project.composeTraceEndSection
|
||||||
@ -96,6 +99,11 @@ fun WeekPager(
|
|||||||
) {
|
) {
|
||||||
(0 until 7).forEach { dayOffset ->
|
(0 until 7).forEach { dayOffset ->
|
||||||
val date = weekMonday.plus(DatePeriod(days = dayOffset))
|
val date = weekMonday.plus(DatePeriod(days = dayOffset))
|
||||||
|
val lunarData = remember(date) {
|
||||||
|
runBlocking {
|
||||||
|
LunarCache.default.getOrCompute(date)
|
||||||
|
}
|
||||||
|
}
|
||||||
DayCell(
|
DayCell(
|
||||||
date = date,
|
date = date,
|
||||||
isCurrentMonth = date.month == selectedDate.month
|
isCurrentMonth = date.month == selectedDate.month
|
||||||
@ -106,7 +114,8 @@ fun WeekPager(
|
|||||||
showLegalHoliday = showLegalHoliday,
|
showLegalHoliday = showLegalHoliday,
|
||||||
onClick = { onDateClick(date) },
|
onClick = { onDateClick(date) },
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
interactionSource = interactionSource
|
interactionSource = interactionSource,
|
||||||
|
lunarData = lunarData
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user