什么是 Easing?
基于时长的
AnimationSpec
操作(如tween
或keyframes
)使用Easing
来调整动画的小数值。这样可让动画值加速和减速,而不是以恒定的速率移动。小数是介于 0(起始值)和 1.0(结束值)之间的值,表示动画中的当前点。Easing 实际上是一个函数,它取一个介于 0 和 1.0 之间的小数值并返回一个浮点数。返回的值可能位于边界之外,表示过冲或下冲。
上面这两段关于什么是 Easing
是官方文档中的描述,是不是看的云里雾里!哈哈哈,第一次看的时候都是,但在介绍 Easing
的最后加了一个注意,一起来看下:
注意:Easing 对象的运行方式与平台中
Interpolator
类的实例相同。不过,它采用的不是getInterpolation()
方法,而是transform()
方法。
奥,原来 Easing
就相当于咱们之前使用的插值器(Interpolator
)啊!这么说就好理解一些了。
如何使用 Easing?
在里面大概介绍了常用的几种 Easing
:
FastOutSlowInEasing
LinearOutSlowInEasing
FastOutLinearEasing
LinearEasing
CubicBezierEasing
其中 CubicBezierEasing
是剩下四种的父类,这里将就不再赘述,如果想看这几种 Easing
的动画效果可以先移步去看下。
下面来看下 Easing
的使用方法:
val value1 by animateFloatAsState(
targetValue = 1f,
animationSpec = tween(
durationMillis = 300,
delayMillis = 50,
easing = LinearOutSlowInEasing // 使用 Easing
)
)
使用方法其实很简单,关键是要选对 Easing
才能实现动画交互想要实现的效果。
还有哪些 Easing?
其实 Compose
中为我们提供的 Easing
远远不止上面说的这几种,还有很多,先来张图感受下有多少吧!
小小提示,并没有截完。。。下面还有,这里就不放那么多截图了。每一种 Easing
都对应着一种动画效果,大家可以去 看每一种 Easing
对应的动画效果样例。
如何自定义 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
中有一个方法 transform
,CubicBezierEasing
类实现了三阶贝塞尔曲线,这相当于原生的 PathInterpolator
。可以看到 CubicBezierEasing
构造方法中接受四个参数,类型都是 Float。
- a:第一个控制点的x坐标。经过点(0,0)和第一个控制点的直线与点(0,0)处的缓动相切
- b:第一个控制点的y坐标。经过点(0,0)和第一个控制点的直线与点(0,0)处的缓动相切
- c:第二个控制点的x坐标。经过点(1,1)和第二个控制点的直线与点(1,1)处的缓动相切
- d:第二个控制点的y坐标。经过点(1,1)和第二个控制点的直线与点(1,1)处的缓动相切。
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
。
最后我根据自己所学所了解所查阅的这些Compose知识点,整理了如下的《JetPack 全家桶学习手册》(内核Comp学习笔记),如需要参考学习:https://0a.fit/GQJSl
《Jetpack 部分》
一、Jetpack之Lifecycle
- 万物基于 Lifecycle
- 手动管理生命周期的痛苦你不懂
- 按照惯例的思考
- 观察者模式
- 引入 Lifecycle 后
- 源码结构
- 简单的源码分析
- activity 生命周期处理
- fragment 生命周期处理
- Lifecycle State 大小比较
二、Jetpack之ViewModel
- ViewModel 的职责
- 作为数据持有者
- Fragment 间共享数据
- 代替 Loader
- 总结
- ViewModel 源码分析
三、Jetpack之DataBinding
- 数据驱动魔法师
- DataBinding 基础
- DataBinding 引入
- 感受魔法的魅力
- 总结
四、Jetpack之Navigation
- 没有 Navigation 的世界
- Navigation 简介
- Navigation 能做什么
- Navigation 工作逻辑
- Navigation Graph
- NavHost
- NavController
- 总结
- ……
五、Jetpack之LiveData
- 我们都是 Adapter
- 理想的数据模型
- LiveData 的错误用法
- 源码结构
- 源码分析
- 总结
如需要参考学习:https://0a.fit/GQJSl
《Compose 知识点部分》
Jetpack Compose入门详解
- 优势与缺点
- 安卓官方Jetpack Compose 四节课
- 标准布局组件
- xml和compose混合使用 + livedata数据绑定
- compose结合navigation使用
- Compose 中的 ConstraintLayout
- Compose 手写一个分享二维码弹窗
- Compose 设置颜色的三种方式
- Compose事件与状态简略介绍
- Compose中的预览@Preview与@PreviewParameter的使用
Compose学习笔记
- 基本控件
- Composable和MutableState
- 重组和无状态
- 状态机制和重组优化
- derivedStateOf和remember的使用
- CompositionLocal的应用场景
- Compose动画之AnimateSpec
- Compose动画之DecayAnimation
- Compose动画之中止和入场效果
Compose 动画使用详解
- Compose 中属性动画的使用探索
- 状态改变动画animateXxxAsState
- 自定义animateXxxAsState动画