Animatable:

  • Animatable是底层的Compose动画实现。之前文章写过的animateXXAsState,其实都是基于Animatable实现的。

AnimationVector

  • 这是 AnimationVector1D、AnimationVector2D、AnimationVector3D 和 AnimationVector4D 的基类。
  • 为了对任意类型进行动画处理,需要提供一个 TwoWayConverter 来定义如何将该任意类型 T 转换为 AnimationVector,反之亦然。
  • 根据这个类型 T 有多少维度,它可能需要转换为 AnimationVector 的任何子类。
  • 例如,基于位置的对象应转换为 AnimationVector2D,而描述矩形边界的对象应转换为 AnimationVector4D。

TwoWayConverter

  • Compose提供的一个用于做某个泛型数据,根据某些规则做转换成AnimationVector的工具库
  • 根据上面的解释,比如我们可以将dp,转换成对应的AnimationVector,让Compose的动画能够针对dp值,去做对应的动画处理。

Dp.VectorConvertor

private val DpToVector: TwoWayConverter<Dp, AnimationVector1D> = TwoWayConverter(
    convertToVector = { AnimationVector1D(it.value) },//将dp转换成AnimationVector1D
    convertFromVector = { Dp(it.value) }//将Vector数据,转换为开发者常用的dp
)

##实用Animatable

  • 用dp作为动画基础,创建Animatable的实例如下:
val anim = remember {
   Animatable(330.dp, Dp.VectorConverter)
   }
  • 动画的运行:
val anim = remember {
    Animatable(330.dp, Dp.VectorConverter)
}
anim.animateTo()//这是一个suspend函数,需要在协程中运行

不能用lifecycleScope.launch{}

  • Compose的重组优化等等相关的特性,导致我们不能直接使用lifecycleScope.launch{}去启动一个协程。
  • 如:
lifecycleScope.launch { //这里IDE会报警:Calls to launch should happen inside a LaunchedEffect and not composition
    anim.animateTo()
}//意思很明确,launch一个协程,需要在LaunchedEffect中
  • 区别: LaunchedEffect启动的协程,在Compose重组优化的过程中,是不会反复执行的,这样能够减少资源损耗。以及如果协程被反复执行,动画肯定也会出问题。

LaunchedEffect

  • 允许我们在Compose的作用域中去启动一个不会在每次重组过程中都启动的协程。
  • 同时,也支持我们传入某些参数,用来决定什么时候,在重组的过程中,去重新launch协程。
LaunchedEffect(Unit){//只看传入的参数在重组时有没有发生改变,改变则重启协程。
    anim.animateTo()
}

animateTo

var scale by remember {
    mutableStateOf(1.0f)//启动一个初始值为1.0f的scale
}
val anim = remember {
    Animatable(scale)//初始的animatable时1.0f
}
LaunchedEffect(scale) {
    anim.animateTo(scale)//当scale发生变化时,重启协程,将animatable,animateTo到scale当前值,也就是1.1f
}
Box(
modifier = Modifier
.width(700.dp)
.height(360.dp)
.scale(anim.value)
.clickable {
    scale = if (scale == 1.0f) {//当点击的时候,切换scale的数值(接下来就能看到,反复点击,View会在1.1f和1.0f的scale倍数下,变换动画)
        1.1f
    } else {
        1.0f
    }
    Toast
        .makeText(
            this@MainActivity,
            "tap daily item",
            Toast.LENGTH_LONG
        )
        .show()
}
) {
    Text("code test for animatable")
}

snapTo

  • animatable的animateTo,可以看到动画过程。
  • 调用snapTo(),会立即生效到对应的targetState,没有动画过程。

 评论