compose动画全解(一)基础动画--AnimationSpec

基础动画规格 AnimationSpec

compose动画最基本的元素AnimationSpec,是compose动画的灵魂,定义了动画如何运动(物理曲线,持续时间,缓动效果等)。

分类

我个人分为两大类:基础动画和循环动画,基础动画包括物理模型的弹簧动画 和时间段的补间动画关键帧动画跳转动画 ;循环动画包含有限和无限 的,都是对时间动画的封装。 具体关系可以看AnimationSpec的继承关系图。


物理模型动画

SpringSpec 弹簧
定义:

使用提供的工厂函数spring构建

kotlin 复制代码
@Stable
public fun <T> spring(
    dampingRatio: Float = Spring.DampingRatioNoBouncy,
    stiffness: Float = Spring.StiffnessMedium,
    visibilityThreshold: T? = null
): SpringSpec<T> = SpringSpec(dampingRatio, stiffness, visibilityThreshold)
参数:
  • dampingRatio : Float
    阻尼强度,越大越弹不动,1f无弹跳动画,0f无限次弹跳。
  • stiffness : Float
    弹性刚度,值越大,弹得越快。
  • visibilityThreshold: T? 动画提前结束的阈值,比如动画状态类型是Float,那么可以设置当目标达到0.1f时就认为动画可以结束了,默认是null。

持续时间动画

TweenSpec 补间动画
定义:

使用提供的工厂函数tween构建

kotlin 复制代码
@Stable
public fun <T> tween(
    durationMillis: Int = DefaultDurationMillis,
    delayMillis: Int = 0,
    easing: Easing = FastOutSlowInEasing
): TweenSpec<T> = TweenSpec(durationMillis, delayMillis, easing)
参数:
  • durationMillis: Int
    动画持续时间
  • delayMillis: Int
    动画延迟多久开始执行
  • easing: Easing
    缓动曲线,一般使用时间维度的贝塞尔曲线CubicBezierEasing

可以在这个网站上看下贝塞尔曲线:贝塞尔曲线在线编辑

KeyframesSpec 关键帧动画

精确控制每一个时间点的动画,相比较tween,可以更精细的控制。

定义:
kotlin 复制代码
@Stable
public fun <T> keyframes(init: KeyframesSpecConfig<T>.() -> Unit): KeyframesSpec<T> {
    return KeyframesSpec(KeyframesSpecConfig<T>().apply(init))
}

参数是一个配置类,看起来比较麻烦,但是compose提供了三个中缀函数at,atFraction,using来传递参数,先看参数解释,再看下面的使用方式:

参数:
  • durationMillis: Int 动画持续时间
  • delayMillis: Int 动画延迟多久开始执行
  • <targetValue> at <time> using <Easing> 目标值时间点 使用缓动曲线
使用:
  1. 一维动画(类型就是Int,Float这种线性的变化)
kotlin 复制代码
keyframes<Int> {
    durationMillis = 3000
    delayMillis = 1000
    0 at 0 using LinearEasing //注意:缓动函数应用的是此帧到下一帧,而不是上一帧到此帧。
    100 atFraction 0.3f  //除了使用具体时间,还可以使用atFraction指定总时间的百分比
    200 at 2000
    ... ...
}
  1. 二维动画(类型是Offset这种位置的变化,x和y轴都会变)
kotlin 复制代码
keyframes<IntOffset> {
    durationMillis = 1000
    
    //Offset这种二维属性除了使用线性的时间缓动,还可以使用路径缓动ArcBelow设置移动的路径。
    IntOffset(0, 0) at 0 using LinearEasing using ArcBelow 

    IntOffset(0, 100) at 1000
}

Ps: ArcBelow只是简单的路径缓动(基于椭圆形),想要精细的控制移动的路径,需要使用PathEasing。

KeyframesWithSplineSpec 平滑的关键帧动画

相比较普通的关键帧动画,它使用了Monotone cubic Hermite spline这种插值算法来对帧节点之间的过渡做平滑处理,普通的关键帧动画使用的是线性插值,意味着在帧节点可能因为设置的变化过大出现突变,但是keyframesWithSplineSpec会自动对帧节点的过渡平滑处理,一定不会出现突变。

periodicBias参数

KeyframesWithSplineSpec有一个重载函数,多了一个periodicBias参数, 这个参数的作用是循环动画中为了实现首尾速度一致(周期性速度连续性),优先修改起始切线速度还是结束切线速度的权重。

compose的注解是一句话:A value from 0f to 1f, indicating how much the starting or ending velocities are modified respectively to achieve periodicity.

详细理解:

  • 速度(Velocity): 在动画中,"速度"可以理解为动画值变化的快慢,对应到样条曲线上就是切线的斜率。斜率越大,变化越快。

  • 周期性(Periodicity): 指的是动画从头到尾播放完后,能够平滑地衔接回开头,形成一个无缝的循环。为了实现这一点,动画结束时的"出速度"应该和开始时的"入速度"相等。

  • 偏向(Bias): periodicBias 就是一个"偏向"或"权重"值。它决定了在多大程度上为了"周期性"而去修改首尾的速度。

那么0f就是完全不考虑周期性,1f就是完全考虑周期性,会让首尾的动画连贯起来。

定义:
kotlin 复制代码
public fun <T> keyframesWithSpline(
    init: KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T>.() -> Unit
): KeyframesWithSplineSpec<T> =
    KeyframesWithSplineSpec(
        config = KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T>().apply(init)
    )

public fun <T> keyframesWithSpline(
    @FloatRange(0.0, 1.0) periodicBias: Float,
    init: KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T>.() -> Unit
): KeyframesWithSplineSpec<T> =
    KeyframesWithSplineSpec(
        config = KeyframesWithSplineSpec.KeyframesWithSplineSpecConfig<T>().apply(init),
        periodicBias = periodicBias,
    )
使用:

跟前面的KeyframesSpec 一样的使用方式,用到中缀函数传递参数。

kotlin 复制代码
keyframesWithSpline(periodicBias = 0.5f) {
	durationMillis = 2000
	1f at 1000 using LinearEasing
},
SnapSpec 跳转动画

这个很简单,无中间过程,立刻跳转到目标值。

定义:
kotlin 复制代码
@Stable public fun <T> snap(delayMillis: Int = 0): SnapSpec<T> = SnapSpec<T>(delayMillis)
ArcAnimationSpec 路径动画

这还是一个试验性质的动画(当前使用的动画版本是1.8.2),主要用于二维移动的路径控制,走一个漂亮弧形。还没有工厂函数提供出来,其中路径模式就是前面关键帧动画使用的ArcMode,其他都是见过的,没啥可讲的,后续版本可能有更多的功能设计。

定义:
kotlin 复制代码
@ExperimentalAnimationSpecApi
@Immutable
public class ArcAnimationSpec<T>(
    public val mode: ArcMode = ArcBelow,
    public val durationMillis: Int = DefaultDurationMillis,
    public val delayMillis: Int = 0,
    public val easing: Easing = FastOutSlowInEasing // Same default as tween()
) : DurationBasedAnimationSpec<T>

重复动画

重复动画已经不是最基础的动画了,是对时间动画的封装使用。

RepeatableSpec 有限动画
定义:
kotlin 复制代码
@Stable
public fun <T> repeatable(
    iterations: Int,
    animation: DurationBasedAnimationSpec<T>,
    repeatMode: RepeatMode = RepeatMode.Restart,
    initialStartOffset: StartOffset = StartOffset(0)
): RepeatableSpec<T> = RepeatableSpec(iterations, animation, repeatMode, initialStartOffset)
参数:
  • iterations: Int
    重复次数
  • animation: DurationBasedAnimationSpec
    时间基础动画
  • repeatMode: RepeatMode
    重复模式(Restart/Reverse)
  • initialStartOffset: StartOffset
    开始动画偏移量,传入偏移时间和偏移类型,类型包括Delay/FastForward

偏移类型的Delay就是等待一段时间后才开始下一轮动画,FastForward意思是下一轮的动画直接从传入的时间点开始,也就是提前执行。

InfiniteRepeatableSpec 无限动画
定义:

和有限动画的区别就是少了重复次数,其他一样的。

kotlin 复制代码
@Stable
public fun <T> infiniteRepeatable(
    animation: DurationBasedAnimationSpec<T>,
    repeatMode: RepeatMode = RepeatMode.Restart,
    initialStartOffset: StartOffset = StartOffset(0)
): InfiniteRepeatableSpec<T> = InfiniteRepeatableSpec(animation, repeatMode, initialStartOffset)

这篇文章学习了compose的所有基础动画,但是没有应用,下篇开始最基本的应用,就可以用代码展现动画效果了,喜欢我的文章请点赞收藏:)

相关推荐
一起搞IT吧43 分钟前
内存泄漏系列专题分析之三十二:高通相机CamX ION/dmabuf内存管理机制CmdBuffer
android·图像处理·数码相机
whysqwhw3 小时前
安卓内存优化
android
用户2018792831674 小时前
TabLayout禁止滑动 + 左对齐排列实现
android
whysqwhw4 小时前
安卓Drawable分类
android
_祝你今天愉快5 小时前
SparseArray & ArrayMap
android·数据结构
2501_916007476 小时前
Charles中文版抓包工具使用指南 提高API调试和网络优化效率
android·ios·小程序·https·uni-app·iphone·webview
叽哥6 小时前
flutter学习第 6 节:按钮与交互组件
android·flutter·ios
xzkyd outpaper6 小时前
Android视图状态以及重绘
android
用户2018792831676 小时前
为什么 Tab 文字默认会全大
android
用户2018792831676 小时前
Tablayout默认情况下,标签为什么会比文字宽?
android