手把手教你写 Compose 动画 -- 流程定制型动画 API:Animatable()

2023-12-07 16:45

本文主要是介绍手把手教你写 Compose 动画 -- 流程定制型动画 API:Animatable(),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

看看官方的解释:

Animatable 是一个值容器,它可以在通过 animateTo 更改值时为值添加动画效果。该 API 支持 animate*AsState 的实现。它可确保一致的连续性和互斥性,这意味着值变化始终是连续的,并且会取消任何正在播放的动画。

Animatable 的许多功能(包括 animateTo)以挂起函数的形式提供。这意味着,它们需要封装在适当的协程作用域内。例如,您可以使用 LaunchedEffect 可组合项针对指定键值的时长创建一个作用域。

反正我刚开始看这段解释有点懵。

老样子,代码引入一步步深入学习:

class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {val anim = Animatable()}}
}

注意:Animatable 导包的时候需要注意,不要选错:

在这里插入图片描述

抱歉,你这样写是会报错的:

在这里插入图片描述

很明显,Animatable 也需要用 remember 包起来:

在这里插入图片描述

提示我们需要加初始值,怎么填呢?我们可以看下 Animatable 的源码:

fun Animatable(initialValue: Float,visibilityThreshold: Float = Spring.DefaultDisplacementThreshold
)

需要一个 Float 类型的初始值:

class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {val anim = remember { Animatable(48f) }}}
}

但并不是不允许用 dp,我们可以这样写也能满足 Animatable 的要求:

class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {val anim = remember { Animatable(48.dp, Dp.VectorConverter) }}}
}

通过 Dp.VectorConverter 可以把 dp 转为 float。

接下来就可以配置动画了,直接调用 animateTo() 函数即可。

在这里插入图片描述

animateTo() 是个 suspend 函数,必须要在协程里面使用:

class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {val anim = remember { Animatable(48.dp, Dp.VectorConverter) }LaunchedEffect(Unit) {anim.animateTo()}}}
}

现在只需要在 animateTo() 里面添加目标值即可。

class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContent {val anim = remember { Animatable(48.dp, Dp.VectorConverter) }LaunchedEffect(Unit) {anim.animateTo(96.dp)}}}
}

到这里 Animatable 就创建好了,现在我们就要可以用起来了:

class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)var big by mutableStateOf(false)setContent {val size = remember(big) { if (big) 96.dp else 48.dp }val anim = remember { Animatable(size, Dp.VectorConverter) }LaunchedEffect(big) {anim.animateTo(size)}Box(Modifier.size(anim.value).background(Color.Blue).clickable {big = !big})}}
}

让我解读下这段代码:

  1. Box 方块的 size 大小取决于 anim 的值,它的值会随着动画逐渐变化。
  2. 点击 Box 会改变 big 值,big 值变化会重新执行 LaunchedEffect 协程,animateTo 会执行,动画启动。
  3. big 从 false -> true,Box 动画由 48.dp -> 96.dp,big 从 true -> false,Box 动画由 96.dp -> 48.dp。

我们看下效果:

在这里插入图片描述

到这里,Animatable 的基本用法就讲完了。

不过 Animatable 还有个特别的功能,我们可以通过 snapTo() 定制动画的初始值。

例如下面的代码:

class MainActivity : ComponentActivity() {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)var big by mutableStateOf(false)setContent {val size = remember(big) { if (big) 96.dp else 48.dp }val anim = remember { Animatable(size, Dp.VectorConverter) }LaunchedEffect(big) {anim.snapTo(if (big) 192.dp else 0.dp)anim.animateTo(size)}Box(Modifier.size(anim.value).background(Color.Blue).clickable {big = !big})}}
}

我们添加了一句:anim.snapTo(if (big) 192.dp else 0.dp)

  1. Box 由小变大时,size 会瞬间到 0dp,然后从 0 -> 48dp
  2. Box 由大变小时,size 会瞬间到 192.dp,然后从 192.dp -> 96dp

看下效果:
在这里插入图片描述

这篇关于手把手教你写 Compose 动画 -- 流程定制型动画 API:Animatable()的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/466605

相关文章

Nginx分布式部署流程分析

《Nginx分布式部署流程分析》文章介绍Nginx在分布式部署中的反向代理和负载均衡作用,用于分发请求、减轻服务器压力及解决session共享问题,涵盖配置方法、策略及Java项目应用,并提及分布式事... 目录分布式部署NginxJava中的代理代理分为正向代理和反向代理正向代理反向代理Nginx应用场景

Spring Boot分层架构详解之从Controller到Service再到Mapper的完整流程(用户管理系统为例)

《SpringBoot分层架构详解之从Controller到Service再到Mapper的完整流程(用户管理系统为例)》本文将以一个实际案例(用户管理系统)为例,详细解析SpringBoot中Co... 目录引言:为什么学习Spring Boot分层架构?第一部分:Spring Boot的整体架构1.1

nodejs打包作为公共包使用的完整流程

《nodejs打包作为公共包使用的完整流程》在Node.js项目中,打包和部署是发布应用的关键步骤,:本文主要介绍nodejs打包作为公共包使用的相关资料,文中通过代码介绍的非常详细,需要的朋友可... 目录前言一、前置准备二、创建与编码三、一键构建四、本地“白嫖”测试(可选)五、发布公共包六、常见踩坑提醒

Ubuntu向多台主机批量传输文件的流程步骤

《Ubuntu向多台主机批量传输文件的流程步骤》:本文主要介绍在Ubuntu中批量传输文件到多台主机的方法,需确保主机互通、用户名密码统一及端口开放,通过安装sshpass工具,准备包含目标主机信... 目录Ubuntu 向多台主机批量传输文件1.安装 sshpass2.准备主机列表文件3.创建一个批处理脚

一个Java的main方法在JVM中的执行流程示例详解

《一个Java的main方法在JVM中的执行流程示例详解》main方法是Java程序的入口点,程序从这里开始执行,:本文主要介绍一个Java的main方法在JVM中执行流程的相关资料,文中通过代码... 目录第一阶段:加载 (Loading)第二阶段:链接 (Linking)第三阶段:初始化 (Initia

使用Go调用第三方API的方法详解

《使用Go调用第三方API的方法详解》在现代应用开发中,调用第三方API是非常常见的场景,比如获取天气预报、翻译文本、发送短信等,Go作为一门高效并发的编程语言,拥有强大的标准库和丰富的第三方库,可以... 目录引言一、准备工作二、案例1:调用天气查询 API1. 注册并获取 API Key2. 代码实现3

Git打标签从本地创建到远端推送的详细流程

《Git打标签从本地创建到远端推送的详细流程》在软件开发中,Git标签(Tag)是为发布版本、标记里程碑量身定制的“快照锚点”,它能永久记录项目历史中的关键节点,然而,仅创建本地标签往往不够,如何将其... 目录一、标签的两种“形态”二、本地创建与查看1. 打附注标http://www.chinasem.cn

通过Docker容器部署Python环境的全流程

《通过Docker容器部署Python环境的全流程》在现代化开发流程中,Docker因其轻量化、环境隔离和跨平台一致性的特性,已成为部署Python应用的标准工具,本文将详细演示如何通过Docker容... 目录引言一、docker与python的协同优势二、核心步骤详解三、进阶配置技巧四、生产环境最佳实践

MyBatis分页查询实战案例完整流程

《MyBatis分页查询实战案例完整流程》MyBatis是一个强大的Java持久层框架,支持自定义SQL和高级映射,本案例以员工工资信息管理为例,详细讲解如何在IDEA中使用MyBatis结合Page... 目录1. MyBATis框架简介2. 分页查询原理与应用场景2.1 分页查询的基本原理2.1.1 分

PHP应用中处理限流和API节流的最佳实践

《PHP应用中处理限流和API节流的最佳实践》限流和API节流对于确保Web应用程序的可靠性、安全性和可扩展性至关重要,本文将详细介绍PHP应用中处理限流和API节流的最佳实践,下面就来和小编一起学习... 目录限流的重要性在 php 中实施限流的最佳实践使用集中式存储进行状态管理(如 Redis)采用滑动