Compose 动画 (八) : Compose中的动画差值器 AnimationSpec

  • Post author:
  • Post category:其他




1. AnimationSpec是什么


Android Compose

中的

AnimationSpec

用来自定义动画规格。

啥意思呢,其实就是类似于

传统View体系

中的差值器

Interpolator

,但是比起差值器,又提供了更多的功能。

根据其不同的子类,可以来控制动画执行时长、设置动画执行多少时间到动画的某个位置、实现仿弹簧的动画效果、指定动画执行次数等等功能。

val alpha: Float by animateFloatAsState(
    targetValue = if (enabled) 1f else 0.5f,
    animationSpec = tween(durationMillis = 300, easing = FastOutSlowInEasing) //这里的tween就是个AnimationSpec
)

先来看下

Compose

中所有的

AnimationSpec

在这里插入图片描述

看上去很多是不是,但实际上我们只需要记住这几个重点的就行

在这里插入图片描述

其中,蓝色背景的是可以直接进行使用的 (实现类),灰色背景的是接口,

AnimationSpec

也是一个接口。

interface AnimationSpec<T> {
    fun <V : AnimationVector> vectorize(
        converter: TwoWayConverter<T, V>
    ): VectorizedAnimationSpec<V>
}



1. SpringSpec


SpringSpec

实现了

AnimationSpec

接口,提供了一些列基于弹簧的物理动画效果。

很多动画内部

AnimationSpec

使用的默认值都是

spring

,比如

animateXXXAsState

以及

updateTransition

等。

因为

spring

的动画效果基于物理原理,使动画更真实自然。

同时,因为

spring

是基于物理规律的,所以无法指定动画执行时长,而是会基于物理规律来确定动画执行时长。

class SpringSpec<T>(
    val dampingRatio: Float = Spring.DampingRatioNoBouncy,
    val stiffness: Float = Spring.StiffnessMedium,
    val visibilityThreshold: T? = null
) : FiniteAnimationSpec<T>


spring

有三个传参,

dampingRatio



stiffness



visibilityThreshold

,前两个参数主要用来控制弹跳动画的动画效果。



1.1 使用示例

var change by remember {
    mutableStateOf(false)
}
val offsetX = remember(change) {
    if (change) 350.dp else 50.dp
}
val offsetXAnim = remember {
    Animatable(offsetX, Dp.VectorConverter)
}
LaunchedEffect(key1 = change, block = {
    offsetXAnim.animateTo(
        offsetX, spring(Spring.DampingRatioMediumBouncy, stiffness = Spring.StiffnessMedium)
    )
})

Box(modifier = Modifier
    .padding(offsetXAnim.value, 0.dp, 0.dp, 0.dp)
    .size(100.dp)
    .background(Color.Blue)
    .clickable { change = !change })

效果如下所示

在这里插入图片描述



1.2 dampingRatio


dampingRation

表示弹簧的阻尼比。这个值越大,阻尼越大。

不同的

dampingRatio

有不同的效果,如下图所示

在这里插入图片描述

如果不额外指定,默认会使用

DampingRationNoBouncy

,是不带弹簧效果的。

需要注意dampingRation不能小于0



1.3 stiffness


stiffness

定义弹簧的刚度值,弹簧有多想变回去,这个值越大,回弹的越快。


Compose



stiffness

定义的常量如下,默认值是

StiffnessMedium

const val StiffnessHigh = 10_000f
const val StiffnessMedium = 1500f
const val StiffnessMediumLow = 400f
const val StiffnessLow = 200f
const val StiffnessVeryLow = 50f

需要注意stiffness必须大于0



1.4 visibilityThreshold


visibilityThreshold

用来指定一个阈值,当动画到达这个阈值时,动画会立即停止。



2. TweenSpec

这里的

Tween

不是老的

View体系

动画中的补间动画,而是和

Interpolator

(差值器)是一个作用的东西。


tween

动画必须在规定时间内完成,它不能像

SpringSpec

那样完全基于物理规律进行动画,

class TweenSpec<T>(
    val durationMillis: Int = DefaultDurationMillis,
    val delay: Int = 0,
    val easing: Easing = FastOutSlowInEasing
)


tween

有3个参数


  • durationMillis

    : 动画执行时间 (

    ms

    )

  • delayMillis

    : 延迟多久开始执行

  • Easing

    : 衰减曲线动画效果,用来配置怎么进行渐变的



2.1 使用示例

var change by remember {
    mutableStateOf(false)
}
val offsetX = remember(change) {
    if (change) 300.dp else 0.dp
}
val offsetXAnim = remember {
    Animatable(offsetX, Dp.VectorConverter)
}
LaunchedEffect(key1 = change, block = {
    //offsetXAnim.animateTo(offsetX, TweenSpec(easing = LinearEasing))
    //tween是TweenSpec的简便写法,这两种都是可以用的
    offsetXAnim.animateTo(
        offsetX, tween(durationMillis = 1000, delayMillis = 0, easing = FastOutSlowInEasing)
    )
})

Box(modifier = Modifier
    .padding(offsetXAnim.value, 0.dp, 0.dp, 0.dp)
    .size(100.dp)
    .background(Color.Blue)
    .clickable { change = !change })

效果如下所示

在这里插入图片描述



2.2 Easing


Compose

中预置的

Easing

有这些

//先加速后减速(默认),相当于差值器中的FastOutSlowInInterpolator
//和AccelerateDecelerateInterpolator类似 (区别和FastOutSlowInInterpolator在于曲线幅度稍有不同,下面几个同理)
val FastOutSlowInEasing: Easing = CubicBezierEasing(0.4f, 0.0f, 0.2f, 1.0f)
//入场速度快,慢慢减速到0,相当于差值器中的LinearOutSlowInInterpolator,和DecelerateInterpolator类似
val LinearOutSlowInEasing: Easing = CubicBezierEasing(0.0f, 0.0f, 0.2f, 1.0f)
//从0慢慢加速到很快,相当于差值器中的FastOutLinearInInterpolator,和AccelerateInterpolator类似
val FastOutLinearInEasing: Easing = CubicBezierEasing(0.4f, 0.0f, 1.0f, 1.0f)
//线性
val LinearEasing: Easing = Easing { fraction -> fraction }



2.2.1 示意曲线

在这里插入图片描述



2.2.2 自定义Easing

使用

CubicBezierEasing

可以自定义

Easing



使用贝塞尔曲线

API

网站 :

cubic-bezier.com

,专门用来展现三阶贝塞尔曲线的效果的,可以查到对应三阶贝塞尔曲线具体的参数,我们传入到

CubicBezierEasing

中就可以自定义

Easing

了。

比如这里


  • FastOutSlowInEasing

    对应的参数是

    CubicBezierEasing(0.4f, 0.0f, 0.2f, 1.0f)

  • LinearOutSlowInEasing

    对应的参数是

    CubicBezierEasing(0.0f, 0.0f, 0.2f, 1.0f)


    在这里插入图片描述



3. SnapSpec

即时生效动画规格,和

anim.snapTo

的效果是一样的

anim.snapTo()
anim.animateTo(offset,SnapSpec(delayMillis=100/*可以设置延迟*/))
anim.animateTo(offset,snap(delayMillis=100/*可以设置延迟*/))



3.1 使用示例

var change by remember {
    mutableStateOf(false)
}
val offsetX = remember(change) {
    if (change) 300.dp else 0.dp
}
val offsetXAnim = remember {
    Animatable(offsetX, Dp.VectorConverter)
}
LaunchedEffect(key1 = change, block = {
    offsetXAnim.animateTo(
        offsetX, snap(delayMillis = 100)
    )
})

Box(modifier = Modifier
    .padding(offsetXAnim.value, 0.dp, 0.dp, 0.dp)
    .size(100.dp)
    .background(Color.Blue)
    .clickable { change = !change })

效果如下所示

在这里插入图片描述



4. KeyframesSpec

关键帧动画规格,相当于可以分段的

tweenSpec

,但是动画的复用性会降低

anim.animateTo(size,keyframes{
	//infix function 中缀函数
	250.dp at 0 with LinearEasing //作用于 0毫秒-150毫秒
	500.dp at 150 with FastOutSlowInEasing//作用于150毫秒及之后  //默认是LinearEasing
	durationMillis = 450 //执行时长
	delayMillis = 50 //延迟多久执行
})

1.until(100) —-> 1 until 100 // 这也是一个中缀函数



4.1 使用示例

var change by remember {
    mutableStateOf(false)
}
val offsetX = remember(change) {
    if (change) 300.dp else 0.dp
}
val offsetXAnim = remember {
    Animatable(offsetX, Dp.VectorConverter)
}
LaunchedEffect(key1 = change, block = {
    offsetXAnim.animateTo(offsetX, keyframes {
        80.dp at 250 with FastOutSlowInEasing //0至150毫秒
        durationMillis = 1000 //动画持续多久
        delayMillis = 50 //延迟多久执行
    })
})

Box(modifier = Modifier
    .padding(offsetXAnim.value, 0.dp, 0.dp, 0.dp)
    .size(100.dp)
    .background(Color.Blue)
    .clickable { change = !change })

显示效果

在这里插入图片描述



5. RepeatableSpec

循环动画规格,

SpringSpec

不能放进

RepeatableSpec

里面,必须是

DurationBasedAnimationSpec

的子类,

SpringSpec

属于物理弹簧效果,真实环境下肯定是无法持续循环的。

fun <T> repeatable(
    iterations: Int, //重复次数
    animation: DurationBasedAnimationSpec<T>, 
    repeatMode: RepeatMode = RepeatMode.Restart, //重复模式 : 重新开始 / 翻转
    initialStartOffset: StartOffset = StartOffset(0) //初始偏移(时间偏移)
)



5.1 使用示例

var change by remember {
    mutableStateOf(false)
}
val offsetX = remember(change) {
    if (change) 300.dp else 0.dp
}
val offsetXAnim = remember {
    Animatable(offsetX, Dp.VectorConverter)
}
LaunchedEffect(key1 = change, block = {
    RepeatMode.Restart
    offsetXAnim.animateTo(offsetX, repeatable(3,tween(),RepeatMode.Reverse))
})

Box(modifier = Modifier
    .padding(offsetXAnim.value, 0.dp, 0.dp, 0.dp)
    .size(100.dp)
    .background(Color.Blue)
    .clickable { change = !change })

效果如下所示

在这里插入图片描述



6. InfiniteRepeatableSpec


InfiniteRepeatableSpec

是无限动画规格,会无限执行。



RepeatableSpec

本质上没有区别,只有一个区别,无限和有限。

anim.animateTo(size, infiniteRepeatable(tween(),RepeatMode.Reverse))

效果如下所示

在这里插入图片描述



7. Compose 动画系列

Compose 动画系列


Compose 动画 (一) : animateXxxAsState 实现放大/缩小/渐变等效果



Compose 动画 (二) : 为什么animateDpAsState要用val ? MutableState和State有什么区别 ?



Compose 动画 (三) : AnimatedVisibility 从入门到深入



Compose 动画 (四) : AnimatedVisibility 各种入场和出场动画效果



Compose 动画 (五) : animateContentSize / animateEnterExit / Crossfade / AnimatedContent



Compose 动画 (六) : 使用Transition管理多个动画,实现动画预览



Compose 动画 (七) : 高可定制性的动画 Animatable



Compose 动画 (八) : Compose中的动画差值器 AnimationSpec

本文为氦客在CSDN上独家发布

地址 :

https://blog.csdn.net/EthanCo/article/details/129882487



版权声明:本文为EthanCo原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。