Compose自定义动画API指南

很多动画API都可以自定义其参数达到不同的效果,Compose也提供了相应的API供开发者进行自定义动画规范。

AnimationSpec

主要用存储动画规格,可以自定义动画的行为,在animate*AsState和updateTransition函数中,此函数默认参数为spring(),也可以说spring是默认的AnimationSpec。

Spring

spring可在起始值和结束值之间创建基于物理特性的动画。可实现类似于弹簧回弹效果的动画,先看看其构造函数:

@Stable
fun <T> spring(dampingRatio: Float = Spring.DampingRatioNoBouncy,stiffness: Float = Spring.StiffnessMedium,visibilityThreshold: T? = null
): SpringSpec<T> =SpringSpec(dampingRatio, stiffness, visibilityThreshold)

这里有2个关键参数:dampingRatio 和 stiffness。其中,dampingRatio定义弹簧的弹性,默认值为Spring.DampingRatioNoBouncy。stiffness定义弹簧应向结束值移动的速度。默认值为 Spring.StiffnessMedium。例如以下示例:

private enum class ShowBoxState { START, END }@ExperimentalAnimationApi
@Preview
@Composable
fun showAnim() {var mBoxState by remember { mutableStateOf(ShowBoxState.START) }val xOffset by animateDpAsState(targetValue = if (mBoxState == ShowBoxState.START) 0.dp else 300.dp,animationSpec = spring(dampingRatio = Spring.DampingRatioMediumBouncy,stiffness = Spring.StiffnessMedium,null))Column() {Row(modifier = Modifier.fillMaxWidth().fillMaxHeight(fraction = 0.1F)) {Box(modifier = Modifier.height(200.dp).absoluteOffset(xOffset).background(Color.Yellow)) {Text(text = "Moving Box!!!")}}Row(modifier = Modifier.fillMaxSize(fraction = 1F),horizontalArrangement = Arrangement.Center) {Button(onClick = {mBoxState =when (mBoxState) {ShowBoxState.START -> ShowBoxState.ENDelse -> ShowBoxState.START}}) {Text(text = "Animate")}}}
}

对应效果为:

Anim-spec-spring.gif

当然,dampingRatio 和 stiffness参数可以自定义很多其他值,例如:

image.gif
等等,这里就不一一说明了。

tween

渐变动画规范,在指定的时间(毫秒)内使用缓和曲线在起始值和结束值之间添加动画,也可以做到延迟效果。

我们按往常惯例,先看其构造函数:

@Stable
fun <T> tween(durationMillis: Int = DefaultDurationMillis,delayMillis: Int = 0,easing: Easing = FastOutSlowInEasing
): TweenSpec<T> = TweenSpec(durationMillis, delayMillis, easing)

可见,其有三个参数,分别为:durationMillis、delayMillis、easing。durationMillis表示动画的时间间隔;delayMillis表示动画播放的延迟时间;easing是用于在开始和结束之间进行插值的缓动曲线接口,其类型为Easing,其源码有定义以下5种常用类型:

@Stable
fun interface Easing {fun transform(fraction: Float): Float
}
val FastOutSlowInEasing: Easing = CubicBezierEasing(0.4f, 0.0f, 0.2f, 1.0f)
val LinearOutSlowInEasing: Easing = CubicBezierEasing(0.0f, 0.0f, 0.2f, 1.0f)
val FastOutLinearInEasing: Easing = CubicBezierEasing(0.4f, 0.0f, 1.0f, 1.0f)
val LinearEasing: Easing = Easing { fraction -> fraction }
@Immutable
class CubicBezierEasing(private val a: Float,private val b: Float,private val c: Float,private val d: Float
) : Easing

感觉其内部构造计算方式跟贝塞尔曲线有关,其实现细节我暂时还没看明白,这里不做赘述,以免误导各位。
示例如下:

@ExperimentalAnimationApi
@Composable
fun showAnim() {var isVisible by remember { mutableStateOf(true) }Column(modifier = Modifier.fillMaxSize(),verticalArrangement = Arrangement.Center,horizontalAlignment = Alignment.CenterHorizontally) {AnimatedVisibility(visible = isVisible,enter = fadeIn(// customize with tween AnimationSpecanimationSpec = tween(durationMillis = 2500,delayMillis = 300,easing = LinearOutSlowInEasing)),// you can also add animationSpec in fadeOut if need be.exit = fadeOut() + shrinkHorizontally(),) {Text(text = "ANIMATION SHOW")}Spacer(modifier = Modifier.height(18.dp))Button(onClick = {isVisible = !isVisible}) {Text(text = "start")}}
}

以上代码中,我们修改渐入动画fadeIn,指定动画规范为tween,动画时长2500ms,延迟300ms以线性方式播放。对应的效果为:

Anim-spec-tween.gif

keyframes

根据在动画时长内的不同时间戳中指定的快照值添加动画效果,效果类似于原生动画中的帧动画,keyframes只有一个参数init,用于动画的初始化,对于动画中每个关键帧,都可以指定 Easing 来确定插值曲线。以下为官方示例:

val value by animateFloatAsState(targetValue = 1f,animationSpec = keyframes {durationMillis = 3750.0f at 0 with LinearOutSlowInEasing // for 0-15 ms0.2f at 15 with FastOutLinearInEasing // for 15-75 ms0.4f at 75 // ms0.4f at 225 // ms}
)

上述代码就是在0毫秒和持续时间处指定值。如果不特殊指定,它们将分别默认为动画的起始值和结束值。示例可通过修改tween()的示例代码看到效果,这里不再赘述。

repeatable

看名字应该就知道了,是重复性动画类别,如果你是这样猜的,那恭喜你猜对了。repeatable反复运行基于时长的动画,直到达到指定的迭代计数。我们先观察其构造函数:

@Stable
fun <T> repeatable(iterations: Int,animation: DurationBasedAnimationSpec<T>,repeatMode: RepeatMode = RepeatMode.Restart
): RepeatableSpec<T> =RepeatableSpec(iterations, animation, repeatMode)

iterations、animation和repeatMode。iterations表示动画重复次数,animation就是要重复的动画,repeatMode用来指定动画是从头开始(RepeatMode.Restart)还是从结尾开始(RepeatMode.Reverse)重复播放。这三个参数足够我们编写精美重复动画了,例如以下示例:

@ExperimentalAnimationApi
@Composable
fun showAnim() {val isShow = remember { mutableStateOf(value = true) }val isEnabled = remember { mutableStateOf(true)}val alpha by animateFloatAsState(targetValue = if (isShow.value) 0.1f else 1.0f,animationSpec = repeatable(iterations = 7, animation = tween(durationMillis = 1000),repeatMode = RepeatMode.Reverse),finishedListener = {isEnabled.value = true})Column(modifier = Modifier.fillMaxSize().background(Color(0xFFEDC9AF)).padding(16.dp),verticalArrangement = Arrangement.spacedBy(16.dp),horizontalAlignment = Alignment.CenterHorizontally) {Button(onClick = {isShow.value = !isShow.valueisEnabled.value = false},colors = ButtonDefaults.buttonColors(Color(0xFF6C541E), Color(0xCCFFFFFF)),enabled = isEnabled.value) {Text(text = "Animation Show! ",modifier = Modifier.padding(12.dp))}Icon(Icons.Filled.Favorite,"",tint = Color(0xFFCE2029),modifier = Modifier.size(300.dp).alpha(alpha = alpha))}
}

对应的效果为:

Anim-spec- repeat.gif

这里是设置了重复次数的,对应也有无重复次数设置的API。

infiniteRepeatable

infiniteRepeatable 与 repeatable 很像,但它会重复无限次的迭代,其构造函数如下:

@Stable
fun <T> infiniteRepeatable(animation: DurationBasedAnimationSpec<T>,repeatMode: RepeatMode = RepeatMode.Restart
): InfiniteRepeatableSpec<T> =InfiniteRepeatableSpec(animation, repeatMode)

可见,其参数相较于repeatable 就少了一个次数限制,其参数含义都一样,有兴趣可以修改repeatable 中的示例,你会发现动画会一直播放,不会停下。这里不再赘述。

snap

主要用于立即将值切换到结束值,很多情况下我们需要提前结束动画,这时就要用到snap()。其构造函数如下:

@Stable
fun <T> snap(delayMillis: Int = 0) = SnapSpec<T>(delayMillis)

可见,这里只有一个参数,延时毫秒数,用来指定延迟动画播放的开始时间。其使用方式如下:

val value by animateFloatAsState(targetValue = 1f,animationSpec = snap(delayMillis = 50)
)

按照官方所言,

在 View 界面系统中,对于基于时长的动画,需要使用 ObjectAnimator 等 API;对于基于物理特性的动画,则需要使用 SpringAnimation。同时使用这两个不同的动画 API 并不容易。但Compose 中的 AnimationSpec 让我们能够以统一的方式处理这些动画。

AnimationVector

大多数 Compose 动画 API 都支持将 Float、Color、Dp 以及其他基本数据类型作为开箱即用的动画值,但有时也需要为其他数据类型(包括您的自定义类型)添加动画效果。其核心意义在于动画播放期间,任何动画值都表示为AnimationVector。使用相应的TwoWayConverter即可将值转换为AnimationVector,反之亦然。例如,用于Int的TwoWayConverter如下所示:

val IntToVector: TwoWayConverter<Int, AnimationVector1D> =     TwoWayConverter({ AnimationVector1D(it.toFloat()) }, { it.value.toInt() })

动画中使用的每种数据类型都可以根据其维度转换为 AnimationVector1D、AnimationVector2D、AnimationVector3D 或 AnimationVector4D(因为Color色值实际上是 red、green、blue 和 alpha 这 4 个值的集合)。目前来说,我还没见过用这个函数的,感觉实际参考意义不大,如果有更好的意见,请留言,大家互相学习。

总结

结合前两篇文章,我们对Compose动画算是有了一个整体认识,前两篇文章为高级别动画和低级别动画,高级别动画是由低级别动画封装而来,低级别动画指的是动画更偏于底层。这里对其常见使用场景做一个梳理:

·AnimatedVisibility : 控制布局显示隐藏;

·animate*Size : 对应布局、颜色、大小等发生变化时可用;

·updateTransition : 存在多个动画,对动画进行组合时可用;

·Animatable : 控制动画初始值等过程时可用。

… …

目前而言,Compose处于起步后加速阶段,官方正在强推,也许迟早会变得常见,就像几年前的Kotlin一样。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/471135.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++】 为什么多继承子类重写的父类的虚函数地址不同?『 多态调用汇编剖析』

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C》《Linux》《算法》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 前言 本篇文章主要是为了解答有…

《剑指offer》

本专题是分享剑指offer的一些题目&#xff0c;开始刷题计划。 二维数组的中的查找【https://www.nowcoder.com/practice/abc3fe2ce8e146608e868a70efebf62e?tpId13&tqId11154&ru/exam/oj】 描述 在一个二维数组array中&#xff08;每个一维数组的长度相同&#xff0…

关于Django的中间件使用说明。

目录 1.中间件2. 为什么要中间件&#xff1f;3. 具体使用中间件3.1 中间件所在的位置&#xff1a;在django的settings.py里面的MIDDLEWARE。3.2 中间件的创建3.3 中间件的使用 4. 展示成果 1.中间件 中间件的大概解释&#xff1a;在浏览器在请求服务器的时候&#xff0c;首先要…

【JAVA-Day88】Java字符串和JSON对象的转换

Java字符串和JSON对象的转换 Java字符串和JSON对象的转换摘要引言一、什么是JSON二、JSON的应用场景三、JSON对象转字符串3.1 使用 Jackson 库实现 JSON 对象转字符串3.2 使用 Gson 库实现 JSON 对象转字符串 四、JSON字符串转对象4.1 使用 Jackson 库实现 JSON 字符串转对象4.…

Editing While Playing 使用 Easyx 开发的 RPG 地图编辑器 tilemap eaitor

AWSD移动画布 鼠标右键长按拖拽 鼠标左键长按绘制 可以边拖拽边移动画布边绘制。 F1 导出 DLC F2 导入DLC author: 民用级脑的研发记录 1309602336qq.com 开发环境&#xff1a; 内置 easyx 的 devc 5.11 或者 VS 2022 TDM GCC 4.9.2 64-bit c11及以上都可运行 windows 环境运行…

通过深度学习和人脸图像进行年龄段估计matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1深度学习网络 4.2 人脸特征提取 4.3 回归模型构建 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022a 3.部分核心程序 ..................................…

平时积累的FPGA知识点(8)

平时在FPGA群聊等积累的FPGA知识点&#xff0c;第八期&#xff1a; 21 FFT IP核 有遇到过FFT IP核测量频率不准确的问题吗&#xff1f;大部分情况下都是准的&#xff0c;偶尔偏差比较大&#xff0c;IP核输入的数据用matlab计算出的频率是对的。 解释&#xff1a;可能是采样点…

docker (三)-开箱即用常用命令

一 docker架构 拉取镜像仓库中的镜像到本地&#xff0c;镜像运行产生一个容器 registry 镜像仓库 registry可以理解为镜像仓库&#xff0c;用于保存docker image。 Docker Hub 是docker官方的镜像仓库&#xff0c;docker命令默认从docker hub中拉取镜像。我们也可以搭建自己…

数据结构——6.1 图的基本概念

第六章 图 6.1 图的基本概念 概念 图的概念&#xff1a;G由点集V和边集E构成&#xff0c;记为G(V,E)&#xff0c;边集可以为空&#xff0c;但是点集不能为空 注意&#xff1a;线性表可以是空表&#xff0c;树可以是空树&#xff0c;但图不可以是空&#xff0c;即V一定是非空集…

Pr教程1-8节笔记

第一课 认识PR以及PR的学习方法 学习任务&#xff1a; 1、熟练掌握PR软件&#xff0c;同时掌握剪辑技术以及常用于制作特效的效果器。 2、认识PR软件的名称、主要功能以及用途作用。 3、明白学习PR我们能做些什么以及PR的学习方法。 知识内容&#xff1a; 1、PR是专门用于视…

Linux 基础/子目录分配/文件路径

在Linux系统中&#xff0c;整个系统只具有一个根目录“/”&#xff0c;用斜杠表示。根目录是整个文件系统的顶层目录&#xff0c;在他下面可以创建其他的目录和文件。 Linux中的子目录分配&#xff1a; /bin - 基本命令的二进制文件&#xff0c;这些命令可供所有用户使用&am…

(10)Hive的相关概念——文件格式和数据压缩

目录 一、文件格式 1.1 列式存储和行式存储 1.1.1 行存储的特点 1.1.2 列存储的特点 1.2 TextFile 1.3 SequenceFile 1.4 Parquet 1.5 ORC 二、数据压缩 2.1 数据压缩-概述 2.1.1 压缩的优点 2.1.2 压缩的缺点 2.2 Hive中压缩配置 2.2.1 开启Map输出阶段压缩&…