所以我有一个 ViewModel,当时间更改时(例如,10:59 -> 11:00),它会将值发布到它的 LiveData 中。 在我的可组合项中,我需要观察 LiveData 和动画背景渐变随时间的变化而变化。 我是这样做的:
@Composable
fun GradientForCurrentTime(viewModel: GradientForCurrentTimeViewModel = viewModel()) {
var gradient by remember {
val currentHour = Date().hours
mutableStateOf(listOf(gradients[currentHour][0], gradients[currentHour][1]))
}
viewModel.currentHour.observeForever { hour ->
val previous = gradient
val new = listOf(gradients[hour][0], gradients[hour][1])
val evaluator = ArgbEvaluator()
val animator: ValueAnimator =
ValueAnimator.ofObject(evaluator, previous[0].toArgb(), new[0].toArgb()).apply {
addUpdateListener {
val newList = listOf(
Color(it.animatedValue as Int), Color(
evaluator.evaluate(
it.animatedFraction,
previous[1].toArgb(),
new[1].toArgb()
) as Int
)
)
gradient = newList
}
duration = 500
}
animator.start()
}
Box(
modifier = Modifier
.fillMaxSize()
.background(
brush = Brush.verticalGradient(gradient)
)
)
}
我的问题来了: 我需要摆脱
observeForever
,因为它显然需要取消订阅,而在这里做到这一点并不那么容易。
另外,我没有看到使用 observeAsState
的最佳方法,因为我已经将 var gradient by remember
作为当前状态来实际绘制渐变。
我当然可以将动画计算移至 ViewModel 中,但它应该是一个选项吗? VeiwModel 应该知道有关动画视图的任何事情吗?
感谢@Hack5的评论,我能够解决我的问题并消除
observeForever
的使用:
@Composable
fun GradientForCurrentTime(viewModel: GradientForCurrentTimeViewModel = viewModel()) {
val currentHour = viewModel.currentHour.observeAsState(Date().hours) //observing current hour from viewModel as state
var startColor by remember { mutableStateOf(gradients[currentHour.value][0]) } //remembering start and end colors of target gradient
var endColor by remember { mutableStateOf(gradients[currentHour.value][1]) }
startColor = gradients[currentHour.value][0] //actually accepting new values for new hour into start and end colors
endColor = gradients[currentHour.value][1]
val startColorAnimate by animateColorAsState(
targetValue = startColor,
animationSpec = tween(500, easing = LinearEasing), label = "startColorAnimate"
) //animate states
val endColorAnimate by animateColorAsState(
targetValue = endColor,
animationSpec = tween(500, easing = LinearEasing), label = "endColorAnimate"
)
Box(
modifier = Modifier
.fillMaxSize()
.background(
brush = Brush.verticalGradient(
listOf(
Color(startColorAnimate.value), //using the animate states' values
Color(endColorAnimate.value)
)
)
)
)
}