如果更改为新动画,UpdateTransition动画会保持其运行速度吗?

Ely*_*lye 5 android android-jetpack-compose

AnimationAsState我使用、Animatable、 和创建相同的动画UpdateTransition并尝试它们。

所有动画都使用向前或向后移动。

    tween(
        durationMillis = 3000,
        easing = LinearOutSlowInEasing
    )
Run Code Online (Sandbox Code Playgroud)

我们可以在下面看到它

在此输入图像描述

如果动画执行到一半,并且我再次单击按钮,我会假设运行的动画速度保持不变并传递到后续动画。

这对于AnimateAsState和 来说似乎是正确的Animatable。然而,令我惊讶的是,他们的UpdateTransition行为似乎并非如此。我猜它已经恢复到默认的动画持续时间(运行得非常快)。

我们可以看到如下。

在此输入图像描述

我的问题是,是吗

  1. UpdateTransition如果后续动画中途取消,预计不会保留正在运行的动画规范?
  2. 我的代码中遗漏了一些内容(我在下面分享了整个代码)?
  3. 这是一个UpdateTransition错误,需要向 Google 报告吗?

上述动画的完整工作代码如下

import androidx.compose.animation.core.*
import androidx.compose.animation.core.Animatable
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material.Button
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp

@Composable
fun Combination() {
    var enabled by remember { mutableStateOf(false) }

    val dbAnimateAsState: Dp by animateDpAsState(
        targetValue = switch(enabled),
        animationSpec = animationSpec()
    )

    val dbAnimatable = remember { Animatable(0.dp) }

    val transition = updateTransition(enabled, label = "")
    val dbTransition by transition.animateDp(
        transitionSpec = { animationSpec() }, label = "") {
        switch(it)
    }

    Column(
        modifier = Modifier.fillMaxSize(),
        verticalArrangement = Arrangement.Center,
        horizontalAlignment = Alignment.CenterHorizontally
    ) {

        Text("AnimateAsState")
        animateBoxHorizontal(dbAnimateAsState)
        Text("Animatable")
        animateBoxHorizontal(dbAnimatable.value)
        Text("UpdateTransition")
        animateBoxHorizontal(dbTransition)

        Button(onClick = { enabled = !enabled }) {
            Text("Click Me")
        }
    }

    LaunchedEffect(key1 = enabled) {
        dbAnimatable.animateTo(
            targetValue = switch(enabled),
            animationSpec = animationSpec()
        )
    }
}

private fun animationSpec(): TweenSpec<Dp> =
    tween(
        durationMillis = 3000,
        easing = LinearOutSlowInEasing
    )

private fun switch(enabled: Boolean) = if (enabled) 268.dp else 0.dp

fun Animatable(initialValue: Dp) = Animatable(
    initialValue,
    DpToVector,
)

private val DpToVector: TwoWayConverter<Dp, AnimationVector1D> =
    TwoWayConverter({ AnimationVector1D(it.value) }, { it.value.dp })

@Composable
private fun animateBoxHorizontal(dbAnimateAsState: Dp) {
    Box(
        modifier = Modifier
            .height(32.dp)
            .width(300.dp)
            .background(Color.Yellow)
    ) {
        Box(
            modifier = Modifier
                .offset(dbAnimateAsState, 0.dp)
                .size(32.dp)
                .background(Color.Red)
        )
    }
    Spacer(modifier = Modifier.height(16.dp))
}
Run Code Online (Sandbox Code Playgroud)

注意:更新信息

如果我从tweenSpec改为springSpecie

    tween(
        durationMillis = 3000,
        easing = LinearOutSlowInEasing
    )
Run Code Online (Sandbox Code Playgroud)

    spring(stiffness =20f, dampingRatio = 0.25f)
Run Code Online (Sandbox Code Playgroud)

然后updateTransition像往常一样工作,当我们用新的动画中断时,弹簧速度和动画将被保留并连续。

Dor*_*Liu 3

updateTransition仍然保持速度 - 如果你可以放慢速度,它可能会更明显。当中断时它会切换到 a spring,而animateAsStateAnimatable使用AnimationSpec您提供的 。该回退弹簧可能有点太硬,因此它被认为是一个非常快的变化。

此设计的目的是允许Transition在使用不同类型的 s 时适应中断AnimationSpec。例如,从状态 A 到状态 B,您可能会使用keyFrames,从状态 B 到状态 C 或可能会使用snap()(因为状态 B 和 C 中的值相同)。因此,当您中断从 A -> B 的动画并以 C 作为新目的地时, 和keyframes都会snap看起来非常奇怪。这就是为什么我们会回退到springaTransition被中断时。

请注意,如果您已经在 中使用 aspring作为动画Transition,则该 spring 将用于处理该动画中的中断,因为它与您的动画更相关。这就是为什么当您为上面代码片段中的过渡提供低刚度弹簧时,您会看到动画的“路线校正”速度要慢得多。

我们确实计划支持中断处理的自定义,您可以在其中指定中断时要使用的 AnimationSpec。这是计划作为未来的工作。如果您对如何处理中断有任何具体要求,或者回退弹簧应该慢一点,请随时提出功能请求。:)