Compose 动画艺术探索之 Easing

2023-01-03  本文已影响0人  代码我写的怎么

本篇文章是此专栏的第六篇文章,前几篇文章大概将 Compose 中的动画都简单过了一遍,如果想阅读前几篇文章的话可以点击下方链接:

什么是 Easing?

基于时长的 AnimationSpec 操作(如 tweenkeyframes)使用 Easing 来调整动画的小数值。这样可让动画值加速和减速,而不是以恒定的速率移动。小数是介于 0(起始值)和 1.0(结束值)之间的值,表示动画中的当前点。

Easing 实际上是一个函数,它取一个介于 0 和 1.0 之间的小数值并返回一个浮点数。返回的值可能位于边界之外,表示过冲或下冲。

上面这两段关于什么是 Easing 是官方文档中的描述,是不是看的云里雾里!哈哈哈,第一次看的时候都是,但在介绍 Easing 的最后加了一个注意,一起来看下:

注意:Easing 对象的运行方式与平台中 Interpolator 类的实例相同。不过,它采用的不是 getInterpolation() 方法,而是 transform() 方法。

奥,原来 Easing 就相当于咱们之前使用的插值器(Interpolator)啊!这么说就好理解一些了。

如何使用 Easing?

其实在之前文章 Compose 动画艺术探索之动画规格 中已经简单介绍过 Easing ,在里面大概介绍了常用的几种 Easing

其中 CubicBezierEasing 是剩下四种的父类,这几种 Easing 的具体用法在 Compose 动画艺术探索之动画规格 中已经介绍过,这里将就不再赘述,如果想看这几种 Easing 的动画效果可以先移步去看下。

下面来看下 Easing 的使用方法:

val value1 by animateFloatAsState(
    targetValue = 1f,
    animationSpec = tween(
        durationMillis = 300,
        delayMillis = 50,
        easing = LinearOutSlowInEasing // 使用 Easing
    )
)

使用方法其实很简单,关键是要选对 Easing 才能实现动画交互想要实现的效果。

还有哪些 Easing?

其实 Compose 中为我们提供的 Easing 远远不止上面说的这几种,还有很多,先来张图感受下有多少吧!

小小提示,并没有截完。。。下面还有,这里就不放那么多截图了。每一种 Easing 都对应着一种动画效果,大家可以去 看每一种 Easing 对应的动画效果样例。下面是官方文档地址:

developer.android.google.cn/reference/k…

如何自定义 Easing?

刚才的截图种可以看到,里面的 Easing 和最初说的那几种都继承的是 CubicBezierEasing ,那咱们就来看下 CubicBezierEasing

@Immutable
class CubicBezierEasing(
    private val a: Float,
    private val b: Float,
    private val c: Float,
    private val d: Float
) : Easing {
    ......
    private fun evaluateCubic(a: Float, b: Float, m: Float): Float {
        return 3 * a * (1 - m) * (1 - m) * m +
            3 * b * (1 - m) *  m * m +
            m * m * m
    }

    override fun transform(fraction: Float): Float {
        if (fraction > 0f && fraction < 1f) {
            var start = 0.0f
            var end = 1.0f
            while (true) {
                val midpoint = (start + end) / 2
                val estimate = evaluateCubic(a, c, midpoint)
                if ((fraction - estimate).absoluteValue < CubicErrorBound)
                    return evaluateCubic(b, d, midpoint)
                if (estimate < fraction)
                    start = midpoint
                else
                    end = midpoint
            }
        } else {
            return fraction
        }
    }
    ......
}

嗯,CubicBezierEasing 实现了 Easing 接口,然后 Easing 中有一个方法 transformCubicBezierEasing 类实现了三阶贝塞尔曲线,这相当于原生的 PathInterpolator 。可以看到 CubicBezierEasing 构造方法中接受四个参数,类型都是 Float。

CubicBezierEasing 是比较复杂的 Easing ,但也是一个通用的,所以有很多 Easing 都继承自它,咱们自定义的时候也可以继承 CubicBezierEasing ,通过传入不同的控制点坐标来实现想要的动画效果。

当然,也可以直接实现 Easing 接口来实现动画效果,比如 LinearEasing

val LinearEasing: Easing = Easing { fraction -> fraction }

由于默认就是线性的,所以直接返回未修改的分数就是线性的动画效果。

接下来咱们来自定义一个 Easing

val CustomLinearEasing: Easing = Easing { fraction -> fraction / 2 }

代码很简单,直接实现 Easing 接口,然后将分数除以二并返回,再来写个 Demo !

var small by remember { mutableStateOf(true) }
val size by animateDpAsState(
    targetValue = if (small) 50.dp else 100.dp,
    animationSpec = tween(
        durationMillis = 3000,
        delayMillis = 50,
        easing = CustomLinearEasing  // 使用上面自定义的 Easing
    )
)

Column {
    Button(onClick = { small = !small }) {
        Text("修改大小")
    }
    Box(
        modifier = Modifier.size(size)
    )
}

代码很简单,在之前的几篇文章中都使用过,这块也就不再赘述,唯一不同的就是这块使用了上面咱们自定义的 Easing

动画执行时间一共是三秒钟,但是三秒钟全部执行在了缩小的前半段,后半段在最后一瞬间完成。这是因为咱们将 Easing 的分数返回值修改为了之前的一半而导致的。

刚才的分数只是除以了二,这回咱们直接改为负数看看!

val CustomLinearEasing: Easing = Easing { fraction -> -fraction / 2 }

别的都没动,只是加了个负号。

可以看到动画效果正好和刚才是相反的方向!

接下来再玩一下,刚才是除以二,这回咱们来乘二看下效果!

val CustomLinearEasing: Easing = Easing { fraction -> fraction * 2 }

可以看到,动画效果执行到目标值还在方法或缩小,最后返回到既定值。

总结

如果想玩好 Compose 中的动画,Easing 是必不可少的一环,其实官方给实现的 Easing 基本都能满足咱们的日程开发需求,如果实现需要自定义那就只能自定义搞一搞了,不过在自定义前可以思考下是直接实现 Easing 接口还是继承 CubicBezierEasing

本文至此结束,有用的地方大家可以参考,当然如果能帮助到大家,哪怕是一点也足够了。就这样。

作者:Zhujiang
链接:https://juejin.cn/post/7169500770344599582

上一篇 下一篇

猜你喜欢

热点阅读