Jetpack Compose惯性衰减动画AnimateDecay详解
vivo祁同伟 人气:0什么是惯性衰减动画
比如说我们玩微信的时候 手指一拉,微信的列表就会惯性滑动 ,这个滑动的速率当然是越来越慢的,最终停止, 这个其实就是惯性衰减动画的典型例子
那这个例子和animateTo 有啥区别呢? 一个速率变慢的动画 ,听起来似乎 我们用animateTo 设置一些参数也可以实现
其实这里最大的区别就是 animateTo 你是需要设置目标值的,也就是动画结束的那一刻 某个view属性的值 你必须明确指定
而所谓的惯性衰减动画 animateDecay 则不需要指定
animateDecay: 从初始速度慢慢停下来 例如松手之后的惯性滑动
animateTo: 指定结束的属性值
看个小例子,来感受一下 模拟的 惯性滑动效果
下面的代码就是以1000.dp的初始速度 开始做惯性动画,直到停下
setContent { val anim = remember { Animatable(0.dp, Dp.VectorConverter) } val re = rememberSplineBasedDecay<Dp>() LaunchedEffect(Unit) { delay(1000) // exponentialDecay<>() // splineBasedDecay<>() android的默认惯性滑动曲线算法 listview rv gridview 之类的 和传统view的overScroller 是一个意思 // rememberSplineBasedDecay() 一般就用待remember的就可以 不带的可以不用 // 这个第一个1000.dp 的参数 代表初始速度 注意这个速度是物理像素值 而不是所谓的速度 // 所以这个值 越大,这个Box的位移 偏移量就越大,可以修改这个值以后感受一下 anim.animateDecay(1000.dp,re) } Box( Modifier .padding(0.dp, anim.value, 0.dp, 0.dp) .size(100.dp) .background(Color.Green)) { } }
注意 splineBasedDecay 一般只能用于 像素的变化,因为这个东西可以针对不同像素密度的设备而变化
exponentialDecay 这个就是典型的不会根据像素密度变化而变化,比如颜色,角度之类的
setContent { val anim = remember { Animatable(0.dp, Dp.VectorConverter) } // frictionMultiplier 代表摩擦力系数 这个值越大 变化的速度就越快 最终反馈的就是 这个box的位移越小 // absVelocityThreshold 速度阈值 大概意思就是 到这个阈值了 就停止了 一般而言 这2个参数 都可以不用设置 默认就好 val decay = exponentialDecay<Dp>(3f,0.5f) LaunchedEffect(Unit) { delay(1000) anim.animateDecay(1000.dp,decay) } Box( Modifier .padding(0.dp, anim.value, 0.dp, 0.dp) .size(100.dp) .background(Color.Green)) { } }
惯性衰减动画 使用要点
上述的代码可能有人要问,为啥你有2个decay,其中一个用的时候有remember开头的函数,还有一个没有?
我们先看那个有的
这里其实是会根据屏幕像素密度的变化而变化的,所以这个值是一个可变的,为了响应这个变化 所以系统默认的给我们提供了remember的这个函数
而 exponentialDecay 则因为不会响应系统的变化,所以不需要,可以直接用,但是 你要是真的直接用了,那就错了 因为 你直接用 那就每次compose页面刷新的时候 他都会初始化一下这个值,这个很没有必要,而且很多时候会出错,所以最佳的做法 还是要remember一下
val decay = remember { exponentialDecay<Dp>(3f,0.5f) }
block 监听
有时 我们使用动画时,会对某一个view使用动画,其他view 响应这个动画的变化 而变化即可,讲白了就是要监听动画的变化,同样的在 compose中 也提供了block这个lambda 可以协助我们完成类似的工作
他是监听动画变化的每一帧,给出对应的回调
如下面的例子所示,这个就是 绿色的box在位移动画,而 黑色的box 跟着绿色的一起变化
setContent { val anim = remember { Animatable(0.dp, Dp.VectorConverter) } // 我们第二个box 就用这个来代表位移吧 var paddingTop by remember { mutableStateOf(anim.value) } val decay = remember { exponentialDecay<Dp>(2f) } LaunchedEffect(Unit) { delay(1000) // 动画的监听 anim.animateDecay(1000.dp, decay) { paddingTop = value } } Row() { Box( Modifier .padding(0.dp, anim.value, 0.dp, 0.dp) .size(100.dp) .background(Color.Green)) { } Box( Modifier .padding(0.dp, paddingTop, 0.dp, 0.dp) .size(100.dp) .background(Color.Black)) { } } }
加载全部内容