Move collapse animation from animateFloatAsState to ViewModel Animatable with spring spec

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
xfy 2026-05-14 14:32:43 +08:00
parent e53c3d8705
commit 35cbcaf430
3 changed files with 34 additions and 15 deletions

View File

@ -1,8 +1,11 @@
package plus.rua.project package plus.rua.project
import androidx.compose.animation.core.Animatable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.datetime.DatePeriod import kotlinx.datetime.DatePeriod
import kotlinx.datetime.LocalDate import kotlinx.datetime.LocalDate
import kotlinx.datetime.TimeZone import kotlinx.datetime.TimeZone
@ -19,7 +22,7 @@ data class CalendarDay(
val isSelected: Boolean val isSelected: Boolean
) )
class CalendarViewModel { class CalendarViewModel(private val coroutineScope: CoroutineScope) {
private val today: LocalDate = Clock.System.todayIn(TimeZone.currentSystemDefault()) private val today: LocalDate = Clock.System.todayIn(TimeZone.currentSystemDefault())
var selectedDate by mutableStateOf(today) var selectedDate by mutableStateOf(today)
@ -28,8 +31,8 @@ class CalendarViewModel {
var isCollapsed by mutableStateOf(false) var isCollapsed by mutableStateOf(false)
private set private set
var collapseProgress by mutableStateOf(0f) private val _collapseAnimatable = Animatable(0f)
private set val collapseProgress: Float get() = _collapseAnimatable.value
val currentYear: Int get() = selectedDate.year val currentYear: Int get() = selectedDate.year
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
@ -40,13 +43,31 @@ class CalendarViewModel {
} }
fun collapse() { fun collapse() {
if (isCollapsed) return
coroutineScope.launch {
_collapseAnimatable.animateTo(
targetValue = 1f,
animationSpec = androidx.compose.animation.core.spring(
dampingRatio = 0.8f,
stiffness = 400f
)
)
isCollapsed = true isCollapsed = true
collapseProgress = 1f }
} }
fun expand() { fun expand() {
if (!isCollapsed) return
isCollapsed = false isCollapsed = false
collapseProgress = 0f coroutineScope.launch {
_collapseAnimatable.animateTo(
targetValue = 0f,
animationSpec = androidx.compose.animation.core.spring(
dampingRatio = 0.8f,
stiffness = 400f
)
)
}
} }
fun getIsoWeekNumber(date: LocalDate): Int { fun getIsoWeekNumber(date: LocalDate): Int {

View File

@ -1,6 +1,5 @@
package plus.rua.project.ui package plus.rua.project.ui
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
@ -37,22 +36,19 @@ fun CalendarMonthPage(
Column(modifier = modifier) { Column(modifier = modifier) {
weeks.forEachIndexed { weekIndex, week -> weeks.forEachIndexed { weekIndex, week ->
val animatedProgress = animateFloatAsState( val progress = collapseProgress
targetValue = collapseProgress,
label = "collapse-$weekIndex"
).value
val isAboveSelected = weekIndex < selectedWeekIndex val isAboveSelected = weekIndex < selectedWeekIndex
val isBelowSelected = weekIndex > selectedWeekIndex val isBelowSelected = weekIndex > selectedWeekIndex
val offsetY = when { val offsetY = when {
isAboveSelected -> -animatedProgress * 200f isAboveSelected -> -progress * 200f
isBelowSelected -> animatedProgress * 200f isBelowSelected -> progress * 200f
else -> 0f else -> 0f
} }
val alpha = when { val alpha = when {
isAboveSelected || isBelowSelected -> 1f - animatedProgress isAboveSelected || isBelowSelected -> 1f - progress
else -> 1f else -> 1f
} }

View File

@ -9,6 +9,7 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -20,9 +21,10 @@ import plus.rua.project.CalendarViewModel
@Composable @Composable
fun CalendarMonthView( fun CalendarMonthView(
viewModel: CalendarViewModel = remember { CalendarViewModel() },
modifier: Modifier = Modifier modifier: Modifier = Modifier
) { ) {
val coroutineScope = rememberCoroutineScope()
val viewModel = remember { CalendarViewModel(coroutineScope) }
val today = remember { Clock.System.todayIn(TimeZone.currentSystemDefault()) } val today = remember { Clock.System.todayIn(TimeZone.currentSystemDefault()) }
var currentYear by remember { mutableIntStateOf(viewModel.currentYear) } var currentYear by remember { mutableIntStateOf(viewModel.currentYear) }
var currentMonth by remember { mutableIntStateOf(viewModel.currentMonth) } var currentMonth by remember { mutableIntStateOf(viewModel.currentMonth) }