本文为稀土技能社区首发签约文章,14天内禁止转载,14天后未获授权禁止转载,侵权必究!

前言

前面文章介绍到的 TweenSpecSnapSpecKeyframesSpace都是完成自 DurationBasedAnimationSpec即动画时长都是确定的,看到这儿可能有些同学就有疑问了?那难道还有动画时长不确定的动画么?是的,比如本篇就要介绍的 SpringSpec

SpringSpec的 Spring 在这儿是绷簧的意思,即绷簧动画标准装备,本篇就带你具体了解其各参数的意义和运用。

SpringSpec

上面说SpringSpec是绷簧动画,那在现实世界中绷簧到底是怎样运动的呢?下面用一张示意图展现一下:

当绷簧被拉离原点放开后,绷簧会弹回原点然后在原点附近震动数次后终究在原点中止,这就是绷簧动画作用,即动画运动到方针值后不会立即中止,而是会依照绷簧特性在方针值附近震动数次后再中止在方针值,而震动的次数和速度就是SpringSpec需求装备的参数。

来看一下 SpringSpec的界说,代码如下:

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

SpringSpec结构办法有三个参数,且都有默认值,参数解析如下:

  • dampingRatio:绷簧阻尼比,数值越小震动的次数越多
  • stiffness:绷簧刚度,刚度越大绷簧回到原点的速度越快,即动画运行得越快
  • visibilityThreshold:可视阈值,即当绷簧弹到某一个值的时候就不弹了然后直接运动到方针值

可通过结构办法或简洁函数 spring办法运用,参数都是一致的,如下:

// 结构办法运用
val springSpec =
        SpringSpec(dampingRatio = 0.1f, 
                   stiffness = 500f, 
                   visibilityThreshold = 0.01.dp)
// spring 简洁函数运用
val springSpec =
        spring(dampingRatio = 0.1f, 
               stiffness = 500f, 
               visibilityThreshold = 0.01.dp)
// 运用
animateDpAsState(targetValue, animationSpec = springSpec)

下面别离来介绍这三个参数的作用和作用。

dampingRatio

阻尼系数越大,弹性运动的震动次数越少、震动起伏越小,阻尼系数有 4 个区间值,别离如下:

  • dampingRatio = 0:无阻尼,绷簧处于永久震动的状况
  • dampingRatio < 1:欠阻尼,绷簧进行指数递减的震动运动
  • dampingRatio = 1:临界阻尼,绷簧以最短时刻结束运动,无震动运动
  • dampingRatio > 1:过阻尼,绷簧进行无震动的减速运动

这儿完成一个小球下落的动画作用示例,为了体现震动的作用,在下落过程中一起增加小球向右的偏移量并用线条制作出小球的运动轨道,完成代码如下:

// 屏幕宽度
val screenWidth = LocalConfiguration.current.screenWidthDp.dp
// 屏幕高度
val screenHeight = LocalConfiguration.current.screenHeightDp.dp
// 制作运动轨道的点
val points = remember { mutableListOf<DpOffset>() }
// 球的大小
val ballSize = 50.dp
// 方针方位
val target = 150.dp
// 操控动画的状况
var moveToRight by remember { mutableStateOf(false) }
// 依据状况核算方针值
val targetValue = if(moveToRight) target else 10.dp
// 球间隔顶部的方位
val topPadding by animateDpAsState(targetValue, animationSpec = spring())
// 球间隔左边的方位
var leftPadding by remember { mutableStateOf(10.dp) }
// 监听 topPadding 的改变修正 leftPadding 值并添加轨道点
val leftPaddingValue = remember(topPadding) {
    leftPadding += 1.dp
    points.add(DpOffset(leftPadding, topPadding))
    leftPadding
}
Box {
    // 方针方位线条
    Box(modifier = Modifier.padding(top = target + ballSize/2 - 1.5.dp).size(screenWidth, 3.dp).background(Color.Green))
    // 小球运动轨道
    Box(modifier = Modifier.size(screenWidth, screenHeight)){
        Canvas(modifier = Modifier.fillMaxSize()) {
            val path = Path()
            path.moveTo(10.dp.toPx(), 10.dp.toPx()+(ballSize/2).toPx())
            if(points.isNotEmpty()){
                points.forEach {
                    path.lineTo(it.x.toPx(), it.y.toPx()+(ballSize/2).toPx())
                }
                drawPath(
                    path = path,
                    color = Color.Red,
                    style = Stroke(
                        width = 3.dp.toPx(),
                    )
                )
            }
        }
    }
    // 小球
    Box(
        Modifier
            // 设置左边和顶部的距离
            .padding(start = leftPaddingValue, top = topPadding)
            .size(ballSize, ballSize)
            .clip(RoundedCornerShape(25.dp))
            .background(Color.Blue)
            .clickable {
                leftPadding = 10.dp
                points.clear()
                moveToRight = true
            }
    )
}

将上面代码中的 spring参数 dampingRatio 设置不同值的看看作用。

  1. dampingRatio = 0
val topPadding by animateDpAsState(targetValue, animationSpec = spring(dampingRatio = 0f))

作用:

咦?作用不对啊,上面不是说当阻尼比为 0 的时候是永久处于震动状况吗?怎样上面的作用并没有震动作用呢?那是由于阻尼比为 0 是一种理论状况,现实世界是不存在的,而 Compose 不支持设置阻尼比为 0,当设置为 0 时尽管代码不会报错但履行实践是没有绷簧作用的。

  1. dampingRatio < 1
val topPadding by animateDpAsState(targetValue, animationSpec = spring(dampingRatio = 0.1f))

这儿设置阻尼比为 0.1f 再来看一下作用:

震动作用就很明显了,小球震动了很多次后才停在了方针方位。

  1. dampingRatio = 1
val topPadding by animateDpAsState(targetValue, animationSpec = spring(dampingRatio = 1f))

作用如下:

没有震动作用,小球减速运动到方针方位。

  1. dampingRatio > 1
val topPadding by animateDpAsState(targetValue, animationSpec = spring(dampingRatio = 10f))

作用:

跟设置 1 时一样没有震动作用,但是运行速度更慢了,当大于 1 时值越大运动速度越慢,动画时长越久。

实践上 Compose 预置了 4 个阻尼比值,如下:

object Spring {
    // 震动作用高
    const val DampingRatioHighBouncy = 0.2f
    // 震动作用中
    const val DampingRatioMediumBouncy = 0.5f
    // 震动作用低
    const val DampingRatioLowBouncy = 0.75f
    // 无震动作用
    const val DampingRatioNoBouncy = 1f
}

别离代表震动作用的高、中、低和无震动作用,默认为无震动作用,在实践开发中咱们一般运用这四种预置的阻尼比值就能完成大部分动画作用,作用比照如下:

从上面的作用比照图中能够看出来,当阻尼比越小时动画震动的次数越多、起伏越大,相反则震动的次数越少、起伏越小,大于等于 1 时无震动。

stiffness

stiffness是绷簧的刚度,刚度越大,反抗绷簧变形的能力越强,回到原点方位的速度就越快,即动画得越快。

相同的 Compose 内置了 5 个刚度值,界说如下:

object Spring {
    // 高刚度
    const val StiffnessHigh = 10_000f
    // 中刚度
    const val StiffnessMedium = 1500f
    // 中低刚度
    const val StiffnessMediumLow = 400f
    // 低刚度
    const val StiffnessLow = 200f
    // 非常低刚度
    const val StiffnessVeryLow = 50f
}

将绷簧阻尼比设置为 DampingRatioHighBouncy时不同刚度值对应的作用如下:

在阻尼比相同的情况下不同刚度值关于动画震动的起伏和次数是一样的,唯一不同的是速度,刚度值越高速度越快,动画时长越短,相反则速度越慢,动画时长越长。

visibilityThreshold

visibilityThreshold是动画的可视阈值,在这儿的作用是当震动起伏小于设置的可视阈值时动画将中止震动并直接运动到方针值。

从文字上理解可能比较笼统,咱们还是以上面的作用为例,当阻尼比设置为 DampingRatioHighBouncy、刚度设置为 StiffnessVeryLow时,通过设置可视阈值别离为默认值 null 、0.1.dp、1.dp、10.dp、100.dp 来看一下作用:

能够发现,当可视阈值设置得越大时,动画中止的越早。

实战

接下来咱们就用 SpringSpec 完成一个简略的实战动画作用,一个点击图片缩放动画作用,运用SpringSpec来完成,代码如下:

// 方针大小
val target = 300.dp
// 缩放状况
var big by remember { mutableStateOf(false) }
// 依据状况的方针值
val targetValue = if (big) target else 100.dp
// 根据动画的图片大小
val size by animateDpAsState(
    targetValue,
    animationSpec = spring(
        // 阻尼比:中
        dampingRatio = Spring.DampingRatioMediumBouncy,
        // 刚度:低
        stiffness = Spring.StiffnessLow
    )
)
Box(Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
    Image(
        painter = painterResource(R.drawable.dog),
        contentDescription = "dog",
        modifier = Modifier
            .size(size)
            .clip(RoundedCornerShape(10.dp))
            .clickable {
                // 改变状况
                big = !big
            },
        contentScale = ContentScale.Crop
    )
}

终究动画作用:

能够发现,在一个一般的图片缩放动画上加上绷簧动画装备后,动画的视觉体会得到了成倍的增加,给用户带来了更好的体会。

最终

本篇具体介绍了绷簧动画标准 SpringSpec的参数装备及对应的运用作用,并用一个简略的实战作用体会了绷簧动画的魅力,至此 6 种动画标准装备现已探究了 4 个,下一篇咱们将持续探究最终两个动画标准:RepeatableSpec(重复动画)、InfiniteRepeatableSpec(无限重复动画),请持续重视本专栏了解更多 Compose 动画相关内容。