当前位置: 首页 > news >正文

Compose 动画 (三) : AnimatedVisibility 从入门到深入

1. AnimatedVisibility 是什么

AnimatedVisibility可以实现Compose组件的显示和隐藏,并且可以指定显示/隐藏时候的动画效果。(EnterTransition/ExitTransition)
和 animateXxxAsState、animateContentSizeCrossfadeAnimatedContent 这几个API一起,都是Compose的高级别动画API,是比较易用的。

2. AnimatedVisibility 的基础使用

@Composable
fun AnimatedVisibilityPage() {Column(horizontalAlignment = Alignment.CenterHorizontally) {var visible by remember {mutableStateOf(true)}AnimatedVisibility(visible = visible) {Image(painter = painterResource(id = R.mipmap.photot1),modifier = Modifier.width(300.dp),contentDescription = null)}Spacer(modifier = Modifier.height(10.dp))Button(onClick = { visible = !visible }) {Text(text = "显示/隐藏")}}
}

看上去是不是很简单,只需要在Image外层包上AnimatedVisibility就可以了,显示效果如下
在这里插入图片描述
我们点进AnimatedVisibility的源码,可以看到如下代码

@Composable
fun ColumnScope.AnimatedVisibility(visible: Boolean,modifier: Modifier = Modifier,enter: EnterTransition = fadeIn() + expandVertically(),exit: ExitTransition = fadeOut() + shrinkVertically(),label: String = "AnimatedVisibility",content: @Composable AnimatedVisibilityScope.() -> Unit
){val transition = updateTransition(visible, label)AnimatedEnterExitImpl(transition, { it }, modifier, enter, exit, content)
}

可以发现其内部调用了updateTransition,该函数内部会返回Transition对象。

@Composable
fun <T> updateTransition(targetState: T,label: String? = null
): Transition<T> {//...省略...
}

Transition可管理一个或多个动画作为其子项,并在多个状态之间同时运行这些动画。
这个我们后续文章会讲到,现在先知道有这样一个概念就好。

3. 入场和出场效果

enterexit,用来配置入场/出场时候的动画效果。

默认的入场效果是 fadeIn() + expandVertically()
默认的出场效果是 fadeOut() + shrinkVertically()

3.1 EnterTransitionExitTransition支持的动画

enter的参数类型是EnterTransition,支持这些动画

  • fade: fadeIn
  • scale: scaleIn
  • slide: slideIn, slideInHorizontally, slideInVertically
  • expand: expandIn, expandHorizontally, expandVertically

exit的参数类型是EnterTransition

  • fade: fadeOut
  • scale: scaleOut
  • slide: slideOut, slideOutHorizontally, slideOutVertically
  • shrink: shrinkOut, shrinkHorizontally, shrinkVertically

可以看到EnterTransitionExitTransition支持的动画只有expandshrink命名上有区别,
其他都是对应的 fadeInfadeOutscaleInscaleOutslideInslideOut
expandshrink命名上做区分,是因为expand就是展开的意思,而shrink收缩的意思,它们其实就是相对应的。

3.1.1 fadeIn / fadeOut

fadeIn / fadeOut是淡出淡出的效果

我们依旧使用上面的那段代码

@Composable
fun AnimatedVisibilityPage() {Column(horizontalAlignment = Alignment.CenterHorizontally) {var visible by remember {mutableStateOf(true)}AnimatedVisibility(visible = visible) {Image(painter = painterResource(id = R.mipmap.photot1),modifier = Modifier.width(300.dp),contentDescription = null)}Spacer(modifier = Modifier.height(10.dp))Button(onClick = { visible = !visible }) {Text(text = "显示/隐藏")}}
}

先把图片部分抽取为一个Composable函数

@Composable
private fun MyImage() {Image(painter = painterResource(id = R.mipmap.photot1),modifier = Modifier.width(300.dp),contentDescription = null)
}

然后修改AnimatedVisibility,配置enterexit

AnimatedVisibility(visible = visible,enter = fadeIn(),exit = fadeOut()
) {MyImage()
}

效果如下所示
在这里插入图片描述

3.1.2 scaleIn / scaleOut

scaleIn / scaleOut是缩放的效果

AnimatedVisibility(visible = visible,enter = scaleIn(),exit = scaleOut()
) {MyImage()
}

效果如下所示
在这里插入图片描述

3.1.3 slideIn / SlideOut

slideIn / SlideOut是滑动的效果,这里进入的初始位置和退出的目标位置都设置为了(300,-150),所以会从右上角进入/退出

AnimatedVisibility(visible = visible,enter = slideIn(initialOffset = {IntOffset(300, -150) }),exit = slideOut(targetOffset = {IntOffset(300,-150) })
) {MyImage()
}

效果如下所示
在这里插入图片描述

3.1.3.1 slideInVertically / slideOutVertically

slideInVertically / slideOutVertically是垂直方向滑动进入/退出

AnimatedVisibility(visible = visible,enter = slideInVertically(),exit = slideOutVertically()
) {MyImage()
}

效果如下所示
在这里插入图片描述

3.1.3.2 slideInHorizontally / slideOutHorizontally

slideInHorizontally / slideOutHorizontally是从横向方向滑动进入/退出

AnimatedVisibility(visible = visible,enter = slideInHorizontally(),exit = slideOutHorizontally()
) {MyImage()
}

效果如下所示
在这里插入图片描述

3.1.4 expandIn / shrinkOut

expandIn / shrinkOut展开/收缩的效果

AnimatedVisibility(visible = visible,enter = expandIn(),exit = shrinkOut()
) {MyImage()
}

效果如下所示
在这里插入图片描述

3.1.4.1 expandVertically / shrinkVertically

expandVertically / shrinkVertically是从垂直方向展开/收缩

AnimatedVisibility(visible = visible,enter = expandVertically(),exit = shrinkVertically()
) {MyImage()
}

效果如下所示
在这里插入图片描述

3.1.4.2 expandHorizontally / shrinkHorizontally

expandHorizontally / shrinkHorizontally是从横向方向展开/收缩

AnimatedVisibility(visible = visible,enter = expandHorizontally(),exit = shrinkHorizontally()
) {MyImage()
}

效果如下所示
在这里插入图片描述

3.1.5 EnterTransitionExitTransition的源码

再来看下源码,入场动画EnterTransition和出场动画ExitTransition内部都有TransitionData变量

sealed class EnterTransition {internal abstract val data: TransitionData//...
}
sealed class ExitTransition {internal abstract val data: TransitionData//...
}

TransitionData即是可配置的动画参数,分别对应fadeslideexpand/shrinkscale

internal data class TransitionData(val fade: Fade? = null,val slide: Slide? = null,val changeSize: ChangeSize? = null,val scale: Scale? = null
)

我们可以发现 EnterTransition 和 ExitTransition 是 sealed class,密封类
其子类可以出现在定义 sealed class 的不同文件中,但不允许出现在与不同的 module 中,且需要保证 package 一致
这样既可以避免 sealed class 文件过于庞大,又可以确保第三方库无法扩展你定义的 sealed class,达到限制类的扩展目的

3.2 +号的作用

AnimatedVisibility源码的部分,入场(enter)和出场(exit)的配置,使用了+,这个加号是用来做什么的呢 ?

首先,+号是Kotlin的一个特性 : 重载运算符

我们点击这个+号,就可以跳转到它的源码

@Stable
operator fun plus(enter: EnterTransition): EnterTransition {return EnterTransitionImpl(TransitionData(fade = data.fade ?: enter.data.fade,slide = data.slide ?: enter.data.slide,changeSize = data.changeSize ?: enter.data.changeSize,scale = data.scale ?: enter.data.scale))}

如果data不为空,就用data的值,否则用enter/exit的。
这里的data就是EnterTransitionExitTransition中的那个变量internal abstract val data: TransitionData(见 3.1 EnterTransitionExitTransition支持的动画部分)

所以fadeIn() + expandVertically()fadeIn()会赋值给TransitionDatafadeexpandVertically会赋值给changeSize

即 : 合并各个动画的效果

3.2.1 两个相同的动画会有什么效果

如果是两个相同的动画,比如fadeIn(initialAlpha = 0.3f) + fadeIn(initialAlpha = 0.5f)
根据源码中的这个规则 如果data不为空,就用data的值,否则用enter/exit的。可知 :
两个fade,会重叠了,导致后面那部分不会生效,等同于fadeIn(initialAlpha = 0.3f)+号左边优先级高

3.3 多种动画效果结合

我们来尝试下多种动画效果,使用+号合并之后的效果

val density = LocalDensity.current
AnimatedVisibility(visible = visible,enter = slideInVertically {//从顶部-200dp的位置开始滑入with(density) { -200.dp.roundToPx() }} + expandHorizontally(//展开位置expandFrom = Alignment.End) + fadeIn(//从初始透明度0.3f开始淡入initialAlpha = 0.3f),exit = slideOutHorizontally() + shrinkHorizontally() + fadeOut()
) {MyImage()
}

效果如下所示
在这里插入图片描述

4. 不同的作用域

4.1 AnimatedVisibility的作用域

AnimatedVisibility有好几种作用域,区别在于在这几种布局中,默认的入场动画出场动画是不同的

Column默认的出入场动画具有垂直展开,而Row的出入场动画具有横向展开Transition无前缀的出入场动画是展开/收缩

Column

fun ColumnScope.AnimatedVisibility(visible: Boolean,modifier: Modifier = Modifier,enter: EnterTransition = fadeIn() + expandVertically(),exit: ExitTransition = fadeOut() + shrinkVertically(),label: String = "AnimatedVisibility",content: @Composable AnimatedVisibilityScope.() -> Unit
)

Row

fun RowScope.AnimatedVisibility(visible: Boolean,modifier: Modifier = Modifier,enter: EnterTransition = fadeIn() + expandHorizontally(),exit: ExitTransition = fadeOut() + shrinkHorizontally(),label: String = "AnimatedVisibility",content: @Composable() AnimatedVisibilityScope.() -> Unit
)

Transition

@ExperimentalAnimationApi //实验的动画API
@Composable
fun <T> Transition<T>.AnimatedVisibility(visible: (T) -> Boolean,modifier: Modifier = Modifier,enter: EnterTransition = fadeIn() + expandIn(),exit: ExitTransition = shrinkOut() + fadeOut(),content: @Composable() AnimatedVisibilityScope.() -> Unit
) = AnimatedEnterExitImpl(this, visible, modifier, enter, exit, content)

无前缀

fun AnimatedVisibility(visible: Boolean,modifier: Modifier = Modifier,enter: EnterTransition = fadeIn() + expandIn(),exit: ExitTransition = shrinkOut() + fadeOut(),label: String = "AnimatedVisibility",content: @Composable() AnimatedVisibilityScope.() -> Unit
)

4.2 使用不了AnimatedVisibility

如果我们在Column里面有个BoxBox里面又有AnimatedVisibility,会发现AnimatedVisibility会报错
在这里插入图片描述

我们把鼠标移到这个报红的地方,可以看到如下的提示

在这里插入图片描述
这边提示

'fun ColumnScope.AnimatedVisibility(visible: Boolean, modifier: Modifier = ..., enter: EnterTransition = ..., exit: ExitTransition = ..., label: String = ..., content: AnimatedVisibilityScope.() -> Unit): Unit' can't be called in this context by implicit receiver. Use the explicit one if necessary

注意最后一句
也就是说,不能使用隐式调用,而必须得用显式的。因为AnimatedVisibility有好几种作用域,ColumnScope和全局的作用域,IDE不知道该引用哪个了。

我们可以显示添加this@Column.,这样,就会引用Column的那个AnimatedVisibility
在这里插入图片描述
当然也可以包装一层Compose函数,使用全局作用域的AnimatedVisibility
在这里插入图片描述
这两种都是可行的

5. 其他

Compose 动画系列,后续持续更新,可以先关注
Compose 动画 (一) : animateXxxAsState 实现放大/缩小/渐变等效果
Compose 动画 (二) : 为什么animateDpAsState要用val ? MutableState和State有什么区别 ?

相关文章:

Compose 动画 (三) : AnimatedVisibility 从入门到深入

1. AnimatedVisibility 是什么 AnimatedVisibility可以实现Compose组件的显示和隐藏&#xff0c;并且可以指定显示/隐藏时候的动画效果。(EnterTransition/ExitTransition) 和 animateXxxAsState、animateContentSize、Crossfade、AnimatedContent 这几个API一起&#xff0c;都…...

网络基础(二)

目录 应用层 再谈 "协议" 协议是一种 "约定". socket api的接口, 在读写数据时, 都是按 "字符串" 的方式来发送接收的. 如果我们要传输一些"结构化的数据" 怎么办呢? 为什么要转换呢&#xff1f; 如果我们将struct message里面…...

Java线程知识点总结

文章目录Java 线程基础线程简介什么是进程什么是线程进程和线程的区别创建线程ThreadRunnableCallable、Future、FutureTaskCallableFutureFutureTaskCallable Future FutureTask 示例线程基本用法线程休眠线程礼让终止线程守护线程线程通信wait/notify/notifyAlljoin管道线程…...

数据结构——第三章 栈与队列(4)

队列的应用1.基于队列的医院挂号模拟系统2.队列的运用1.基于队列的医院挂号模拟系统 代码实现分享 2.队列的运用 问题描述&#xff1a;某运动会设立N个比赛项目&#xff0c;每个运动成员可以参加1~3个项目。试问如何安排比赛日程&#xff0c;既可以使同一运动员参加的项目不…...

华为机试HJ73-计算日期到天数转换

HJ73 计算日期到天数转换 题目描述&#xff1a; 描述 根据输入的日期&#xff0c;计算是这一年的第几天。 保证年份为4位数且日期合法。 进阶&#xff1a;时间复杂度&#xff1a;O(n) &#xff0c;空间复杂度&#xff1a;O(1) 输入描述&#xff1a; 输入一行&#xff0c;每行…...

【阅读笔记】你不知道的JavaScript--this与对象2

目录this默认绑定隐式绑定隐式丢失显示绑定API 调用上下文new 绑定this 绑定优先级其余绑定例外对象字面量与对象属性描述符迭代器遍历this 默认绑定 默认绑定适配 独立函数调用 默认绑定 this 指向全局对象&#xff1b; 故直接调用函数&#xff0c;该函数内部的 this 即指向全…...

单板TVS接地不当造成辐射骚扰超标问题分析-EMC

【摘要】 某产品EMC辐射骚扰测试超标&#xff0c;通过近远场扫描配合定位分析&#xff0c;逐步找出骚扰源、传播路径&#xff0c;最终通过修改 PCB 走线切断传播路径解决此问题。 1 故障现象 某产品在进行 EMC 研发摸底测试时发现&#xff0c;整机辐射骚扰垂直方向测试超标&a…...

用Python Flask为女朋友做一个简单的网站(附可运行的源码)

&#x1f31f;所属专栏&#xff1a;献给榕榕&#x1f414;作者简介&#xff1a;rchjr——五带信管菜只因一枚&#x1f62e;前言&#xff1a;该专栏系为女友准备的&#xff0c;里面会不定时发一些讨好她的技术作品&#xff0c;感兴趣的小伙伴可以关注一下~&#x1f449;文章简介…...

vue3+rust个人博客建站日记5-所有界面

没有数据的前端&#xff0c;是没有灵魂的。明明标题是vue3 rust &#xff0c;但日记撰写至今&#xff0c;似乎只有第一篇提及了Rust&#xff0c;这可不行。是时候一股作气&#xff0c;完成大部分页面绘制工作了&#xff01; 最后再说一次&#xff0c;时间要加速了。 ——普奇神…...

青少年软件编程C++一级真题(202212)

1、输入一个整数x&#xff0c;输出这个整数加1后的值&#xff0c;即x1的值。 时间限制&#xff1a;1000 内存限制&#xff1a;65536 输入 一个整数x&#xff08;0 ≤ x ≤ 1000&#xff09;。 输出 按题目要求输出一个整数。 样例输入 9样例输出 10 #include<iost…...

【Spring】AOP底层原理(动态代理)-》 AOP概念及术语 -》 AOP实现

个人简介&#xff1a;Java领域新星创作者&#xff1b;阿里云技术博主、星级博主、专家博主&#xff1b;正在Java学习的路上摸爬滚打&#xff0c;记录学习的过程~ 个人主页&#xff1a;.29.的博客 学习社区&#xff1a;进去逛一逛~ AOP - 面向切面编程一、简述AOP二、AOP底层原理…...

Java8 新特性 之 lambda 表达 和 函数式接口

—— lambda 表达式 概念 lambda 表达式是一个匿名函数&#xff0c;可以把 lambda 表达式理解为是一段可以传递的代码。更简洁、更灵活&#xff0c;使 Java 的语言表达能力得到了提升lambda 表达式是作为接口的实现类的对象&#xff08;万事万物皆对象&#xff09; 使用语法…...

Netty服务端和客户端开发实例

一、Netty服务端开发在开始使用 Netty 开发 TimeServer 之前&#xff0c;先回顾一下使用 NIO 进行服务端开发的步骤。(1)创建ServerSocketChannel&#xff0c;配置它为非阻塞模式;(2)绑定监听&#xff0c;配置TCP 参数&#xff0c;例如 backlog 大小;(3)创建一个独立的I/O线程&…...

linux基本指令和权限

目录 一.shell命令以及运行原理 二.Linux常用指令 1. ls 指令 2. pwd命令 3.cd指令 4. touch指令 5.mkdir指令&#xff08;重要&#xff09; 6.rmdir指令 && rm 指令&#xff08;重要&#xff09; 7.man指令&#xff08;重要&#xff09; 8.cp指令&#xff08;重要&…...

滚蛋吧,正则表达式!

大家好&#xff0c;我是良许。 不知道大家有没有被正则表达式支配过的恐惧&#xff1f;看着一行火星文一样的表达式&#xff0c;虽然每一个字符都认识&#xff0c;但放在一起直接就让人蒙圈了~ 你是不是也有这样的操作&#xff0c;比如你需要使用「电子邮箱正则表达式」&…...

序列号和反序列化--java--Serializable接口--json序列化普通使用

序列化和反序列化序列化和反序列化作用为什么需要用途Serializable使用serialVersionUID不设置的后果什么时候修改Externalizable序列化的顺序json序列化序列化和反序列化 序列化&#xff1a;把对象转换为字节序列的过程称为对象的序列化。 反序列化:把字节序列恢复为对象的过…...

Java异步任务编排

多线程创建的五种方式&#xff1a; 继承Thread类实现runnable接口。实现Callable接口 FutureTask(可以拿到返回结果&#xff0c;阻塞式等待。)线程池创建。 ExcutorService service Excutors.newFixedThreadPool(10); service.excute(new Runnable01());另外一种创建线程池…...

Hive与HBase的区别及应用场景

当数据量达到一定量级的时候&#xff0c;存储和统计计算查询都会遇到问题&#xff0c;今天了解一下Hive和Hbase的区别和应用场景。 一、定义 Hive是基于Hadoop的一个数据仓库工具&#xff0c;可以将结构化的数据文件映射为一张数据库表&#xff0c;并提供简单的sql查询功能&am…...

C++之单例模式

目录 1. 请设计一个类&#xff0c;只能在堆上创建对象 2. 请设计一个类&#xff0c;只能在栈上创建对象 3.请设计一个类&#xff0c;不能被拷贝 C98 C11 4. 请设计一个类&#xff0c;不能被继承 C98 C11 5. 请设计一个类&#xff0c;只能创建一个对象(单例模式) 设计…...

Redis十大类型——Set与Zset常见操作

Redis十大类型——Set与Zset常见操作Set命令操作简列基本操作展示删除移动剪切集合运算Zset基本操作简列添加展示反转按分数取值获取分数值删除分数操作下标操作如果我们对Java有所了解&#xff0c;相信大家很容易就明白Set&#xff0c;在Redis中也一样&#xff0c;Set的value值…...

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...

C++初阶-list的底层

目录 1.std::list实现的所有代码 2.list的简单介绍 2.1实现list的类 2.2_list_iterator的实现 2.2.1_list_iterator实现的原因和好处 2.2.2_list_iterator实现 2.3_list_node的实现 2.3.1. 避免递归的模板依赖 2.3.2. 内存布局一致性 2.3.3. 类型安全的替代方案 2.3.…...

【决胜公务员考试】求职OMG——见面课测验1

2025最新版&#xff01;&#xff01;&#xff01;6.8截至答题&#xff0c;大家注意呀&#xff01; 博主码字不易点个关注吧,祝期末顺利~~ 1.单选题(2分) 下列说法错误的是:&#xff08; B &#xff09; A.选调生属于公务员系统 B.公务员属于事业编 C.选调生有基层锻炼的要求 D…...

深入解析C++中的extern关键字:跨文件共享变量与函数的终极指南

&#x1f680; C extern 关键字深度解析&#xff1a;跨文件编程的终极指南 &#x1f4c5; 更新时间&#xff1a;2025年6月5日 &#x1f3f7;️ 标签&#xff1a;C | extern关键字 | 多文件编程 | 链接与声明 | 现代C 文章目录 前言&#x1f525;一、extern 是什么&#xff1f;&…...

自然语言处理——循环神经网络

自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元&#xff08;GRU&#xff09;长短期记忆神经网络&#xff08;LSTM&#xff09…...

css3笔记 (1) 自用

outline: none 用于移除元素获得焦点时默认的轮廓线 broder:0 用于移除边框 font-size&#xff1a;0 用于设置字体不显示 list-style: none 消除<li> 标签默认样式 margin: xx auto 版心居中 width:100% 通栏 vertical-align 作用于行内元素 / 表格单元格&#xff…...

听写流程自动化实践,轻量级教育辅助

随着智能教育工具的发展&#xff0c;越来越多的传统学习方式正在被数字化、自动化所优化。听写作为语文、英语等学科中重要的基础训练形式&#xff0c;也迎来了更高效的解决方案。 这是一款轻量但功能强大的听写辅助工具。它是基于本地词库与可选在线语音引擎构建&#xff0c;…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…...

腾讯云V3签名

想要接入腾讯云的Api&#xff0c;必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口&#xff0c;但总是卡在签名这一步&#xff0c;最后放弃选择SDK&#xff0c;这次终于自己代码实现。 可能腾讯云翻新了接口文档&#xff0c;现在阅读起来&#xff0c;清晰了很多&…...

FFmpeg:Windows系统小白安装及其使用

一、安装 1.访问官网 Download FFmpeg 2.点击版本目录 3.选择版本点击安装 注意这里选择的是【release buids】&#xff0c;注意左上角标题 例如我安装在目录 F:\FFmpeg 4.解压 5.添加环境变量 把你解压后的bin目录&#xff08;即exe所在文件夹&#xff09;加入系统变量…...