Jetpack Compose“最短”旋转动画

ikn*_*now 5 animation android kotlin android-jetpack-compose

我试图在jetpack compose中做一个指南针。但我在制作动画时遇到了问题。我有一个@Composable可以让用户手机旋转并以相反方向旋转罗盘图像的功能。我animateFloatAsState这样使用:

val angle: Float by animateFloatAsState(
    targetValue = -rotation, \\ rotation is retrieved as argument
    animationSpec = tween(
        durationMillis = UPDATE_FREQUENCY, \\ rotation is retrieved with this frequency
        easing = LinearEasing
    )
)

Image(
    modifier = Modifier.rotate(angle),
    // rest of the code for image
)
Run Code Online (Sandbox Code Playgroud)

一切看起来都很好,但是当从到或以相反的方式rotation更改时,就会出现问题。动画不会向左旋转角度,而是向右旋转角度,这看起来很糟糕。有没有什么方法可以用最短的方式制作旋转动画?13592358

ikn*_*now 4

我最终这样做了:

val (lastRotation, setLastRotation) = remember { mutableStateOf(0) } // this keeps last rotation
var newRotation = lastRotation // newRotation will be updated in proper way
val modLast = if (lastRotation > 0) lastRotation % 360 else 360 - (-lastRotation % 360) // last rotation converted to range [-359; 359]
    
if (modLast != rotation) // if modLast isn't equal rotation retrieved as function argument it means that newRotation has to be updated
{
    val backward = if (rotation > modLast) modLast + 360 - rotation else modLast - rotation // distance in degrees between modLast and rotation going backward 
    val forward = if (rotation > modLast) rotation - modLast else 360 - modLast + rotation // distance in degrees between modLast and rotation going forward
    
    // update newRotation so it will change rotation in the shortest way
    newRotation = if (backward < forward)
    {
        // backward rotation is shorter
        lastRotation - backward
    }
    else
    {
        // forward rotation is shorter (or they are equal)
        lastRotation + forward
    }
    
    setLastRotation(newRotation)
}

val angle: Float by animateFloatAsState(
    targetValue = -newRotation.toFloat(),
    animationSpec = tween(
        durationMillis = UPDATE_FREQUENCY,
        easing = LinearEasing
    )
)
Run Code Online (Sandbox Code Playgroud)

所以基本上我记住了最后一次旋转,并基于此,当新的旋转出现时,我检查哪种方式(向前或向后)更短,然后用它来更新目标值。