Compose自定义动画API指南

news2025/1/15 19:56:21

很多动画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.END
                        else -> 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 AnimationSpec
                animationSpec = 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 = 375
        0.0f at 0 with LinearOutSlowInEasing // for 0-15 ms
        0.2f at 15 with FastOutLinearInEasing // for 15-75 ms
        0.4f at 75 // ms
        0.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.value
                isEnabled.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.coloradmin.cn/o/1450585.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习——聚类问题

&#x1f4d5;参考&#xff1a;西瓜书ysu老师课件博客&#xff08;3&#xff09;聚类算法之DBSCAN算法 - 知乎 (zhihu.com) 目录 1.聚类任务 2.聚类算法的实现 2.1 划分式聚类方法 2.1.1 k均值算法 k均值算法基本原理&#xff1a; k均值算法算法流程&#xff1a; 2.2 基于…

语言与真实世界的关系(超级语言生成能力将促进世界深刻变化)

语言与真实世界之间存在着紧密且复杂的关系。在人类社会中&#xff0c;语言是认知、表达和交流现实世界的主要工具&#xff0c;它帮助我们构建并理解周围环境&#xff0c;并将我们的思维和经验概念化。 1. 符号与指代&#xff1a; 语言是一种符号系统&#xff0c;通过词汇、句…

SG3225EEN晶体振荡器规格书

SG3225EEN 晶振是EPSON/爱普生的一款额定频率25 MHz至500 MHz的石英晶体振荡器&#xff0c;6脚贴片&#xff0c;LV-PECL输出&#xff0c;3225封装常规有源晶振&#xff0c;具有小尺寸&#xff0c;轻薄型&#xff0c;高稳定性&#xff0c;低相位抖动&#xff0c;低电源电压&…

17.3.1.2 曝光

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 基本算法&#xff1a;先定义一个阈值&#xff0c;通常取得是128 原图像&#xff1a;颜色值color&#xff08;R&#xff0c;G&#…

OpenTitan- 开源安全芯片横空出世

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

【前端web入门第六天】02 flex布局

文章目录 Flex布局1.Flex组成2.主轴与侧轴对齐方式2.1 主轴对齐方式(横轴)2.2 侧轴对齐方式 (纵轴)2.3 修改主轴方向 3.弹性伸缩比4.弹性换行与行对齐方式4.1 弹性换行4.2 行对齐方式 Flex布局 1.Flex组成 设置方式:给父元素设置display: flex&#xff0c;子元素可以自动挤压…

找负环(图论基础)

文章目录 负环spfa找负环方法一方法二实际效果 负环 环内路径上的权值和为负。 spfa找负环 两种基本的方法 统计每一个点的入队次数&#xff0c;如果一个点入队了n次&#xff0c;则说明存在负环统计当前每个点中的最短路中所包含的边数&#xff0c;如果当前某个点的最短路所…

【C++】---类和对象(上)入门

一、类的定义 1.那么众所周知&#xff0c;C语言是面向过程的&#xff0c;关注的是过程&#xff0c;分析出求解的步骤&#xff0c;通过函数的调用来逐步解决问题 2.而C是基于面向对象的&#xff0c;关注的是对象&#xff0c;将一件事情拆分成不同的对象&#xff0c;靠对象之间交…

【自然语言处理】:实验1布置,Word2VecTranE的实现

清华大学驭风计划 因为篇幅原因实验答案分开上传&#xff0c;答案链接http://t.csdnimg.cn/5cyMG 如果需要详细的实验报告或者代码可以私聊博主 有任何疑问或者问题&#xff0c;也欢迎私信博主&#xff0c;大家可以相互讨论交流哟~~ 实验1&#xff1a; Word2Vec&TranE的…

使用HTML、CSS和JavaScript构建响应式企业官网

使用HTML、CSS和JavaScript构建响应式企业官网&#xff0c;web网页设计与制作-htmlcssjs实现企业官网展示。 页面效果展示 pc端和移动端 动态演示 文件目录 assets文件夹&#xff1a;静态资源目录&#xff0c;主要存放css、fonts、images、js等静态资源文件&#xff1b; fa…

Unity如何修改预制体(预制件)?

文章目录 19 复制复制复制&#xff0c;预制体与变体 19 复制复制复制&#xff0c;预制体与变体 【预制件】 预制件作用&#xff1a;方便复用 【预制件】的制作 直接拖拽&#xff0c;从层级面板 -> 项目面板。层级面板中当前图标会变蓝&#xff0c;子物体名字变蓝色。预制件…

《PCI Express体系结构导读》随记 —— 第II篇 第13章 PCI总线与虚拟化技术(5)

接前一篇文章&#xff1a;《PCI Express体系结构导读》随记 —— 第II篇 第13章 PCI总线与虚拟化技术&#xff08;4&#xff09; 13.1 IOMMU 13.1.3 AMD处理器的IOMMU AMD处理器的IOMMU技术与Intel的VT-d技术类似&#xff0c;其完成的主要功能也类似。AMD率先提出了IOMMU的概念…

(11)Hive调优——explain执行计划

一、explain查询计划概述 explain将Hive SQL 语句的实现步骤、依赖关系进行解析&#xff0c;帮助用户理解一条HQL 语句在底层是如何实现数据的查询及处理&#xff0c;通过分析执行计划来达到Hive 调优&#xff0c;数据倾斜排查等目的。 官网指路&#xff1a; https://cwiki.ap…

【网站项目】228高校教师电子名片系统

&#x1f64a;作者简介&#xff1a;拥有多年开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

Vi 和 Vim 编辑器

Vi 和 Vim 编辑器 vi 和 vim 的基本介绍 Linux 系统会内置 vi 文本编辑器 Vim 具有程序编辑的能力&#xff0c;可以看做是 Vi 的增强版本&#xff0c;可以主动的以字体颜色辨别语法的正确性&#xff0c;方便程序设计。 代码补完、编译及错误跳转等方便编程的功能特别丰富&…

智慧供应链控制塔大数据解决方案

一、供应链控制塔的概念定义 (1) Gartner 的定义: “控制塔是一个物理或虚拟仪表板,提供准确的、及时的、完整的物流事件和数据,从组织和服务的内部和跨组织运作供应链,以协调所有相关活动。”、“供应链控制塔…提供供应链端到端整体可见性和近实时信息和决策的概念……

基于PSO优化的LSTM多输入分类(Matlab)粒子群优化长短期神经网络分类

目录 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 亮点与优势&#xff1a; 二、实际运行效果&#xff1a; 三、部分代码展示&#xff1a; 四、完整代码数据分享下载&#xff1a; 一、程序及算法内容介绍&#xff1a; 基本内容&#xff1a; 本代码基于Matal…

数据库第二次实验

目录 1 实验内容 2 SQL代码及运行截图 2.1 创建表并插入数据 2.1.1 创建表 2.1.2 插入数据 2.1.3 运行截图 2.2 修改表 2.2.1 SQL代码 2.2.2 运行截图 2.3 删除操作 2.3.1 SQL代码 2.3.2 运行截图 2.4 数据库的备份 2.5 数据库的恢复 1 实验内容 实验目的&#…

暴力枚举刷题1

题目来源&#xff1a;统计方形&#xff08;数据加强版&#xff09; - 洛谷 参考书籍&#xff1a;《深入浅出程序设计竞赛&#xff08;基础篇&#xff09;》 解题思路&#xff1a;这道理适合用暴力枚举求解。我把书上提到的四种枚举方法分享给大家。 解题1&#xff1a;减少枚…

【AI绘画】硬核解读Stable Diffusion(完整版) 小白必收藏!!!

手把手教你入门绘图超强的AI绘画&#xff0c;用户只需要输入一段图片的文字描述&#xff0c;即可生成精美的绘画。给大家带来了全新保姆级教程资料包 &#xff08;文末可获取&#xff09; 2022年可谓是AIGC&#xff08;AI Generated Content&#xff09;元年&#xff0c;上半年…