前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一文了解如何使用Compose动画~

一文了解如何使用Compose动画~

作者头像
黄林晴
发布2022-05-10 15:00:53
1.1K0
发布2022-05-10 15:00:53
举报
文章被收录于专栏:代码男人代码男人

前言

断断续续学习Compose已经快有一个月了,在编写“正在加载框”这个效果时,遇到了动画相关的问题。当然Lottie框架也已经支持Compose了,但学习和了解Compose动画的基础知识还是很有必要的,本篇文章就来一起了解Compose动画的实现~

动画的种类

动画的种类就很多,根据使用场景有AnimationVisibility、rememberInfiniteTransition、Animation等。如果你想知道在你的需求场景中需要使用什么动画,可以参照官方的这张流程指示图。

AnimationVisibility

AnimationVisibility可以为布局中的内容变化添加动画效果,比如内容的显示、隐藏等效果。

我们用AnimationVisibility来实现控制图片的显示与隐藏,首先定义变量用来控制图片是否显示,代码如下所示:

代码语言:javascript
复制
var visible by remember {
  mutableStateOf(false)                     
}

默认不显示,使用AnimatedVisibility函数将图片组件包裹

代码语言:javascript
复制
AnimatedVisibility(
    visible = visible
) {
    Image(
        painter = painterResource(id = R.mipmap.photon),
        contentDescription = null
    )
}

添加一个Button,用于控制图片的显示与隐藏,代码如下所示:

代码语言:javascript
复制
Button(modifier = Modifier.padding(vertical = 5.dp), onClick = {
    visible = !visible
}) {
    val value = if (visible) {
        "隐藏"
    } else {
        "显示"
    }
    Text(text = value)
}

运行程序,效果图如下所示。

从效果图中可以看出,图片出现时有自上到下弹入的效果,图片消失时有自下到上弹出的效果。那么这个动画效果是如何实现的呢?AnimatedVisibility函数的源码如下所示:

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

visible参数用于控制是否显示,enter、exit参数分别用来设置动画进入和退出的效果。这里设置了默认效果。在EnterTransition这个密封类中定义了fadeIn、fadeOut、slideIn、slideOut 以及scaleIn、scaleOut动画效果。动画效果是可以自由组合的,如上源码所示为动画进入设置了fadeIn+expandVertically的组合效果。

接着我们自己设置动画效果为scaleIn和scaleOut,修改代码如下所示:

代码语言:javascript
复制
AnimatedVisibility(
    visible = visible,
    enter = scaleIn(),
    exit = scaleOut()
) {
    Image(
        painter = painterResource(id = R.mipmap.photon),
        contentDescription = null
    )
}

运行程序,效果图如下所示。

从效果图可以看出scaleIn和scaleOut的效果为从中间扩散和向中间聚集的效果。更多的效果显示,读者可自行尝试。

AnimatedContent

AnimatedContent可以设定目标内容,当目标内容变化时,为内容添加动画效果。以点击按钮改变data变量值为例,代码如下所示:

代码语言:javascript
复制
Column() {
    var data by remember { mutableStateOf(0) }
    Button(onClick = { data++ }) {
        Text("添加数据")
    }

    AnimatedContent(targetState = data) {
        Text(text = "数值:${data}")
    }

}

 运行程序,效果图如下所示。

从效果图中可以看出,在数值变化的时候,会有淡入淡出的效果。AnimatedContent函数源码如下所示:

代码语言:javascript
复制
@ExperimentalAnimationApi
@Composable
fun <S> AnimatedContent(
    targetState: S,
    modifier: Modifier = Modifier,
    transitionSpec: AnimatedContentScope<S>.() -> ContentTransform = {
        fadeIn(animationSpec = tween(220, delayMillis = 90)) +
            scaleIn(initialScale = 0.92f, animationSpec = tween(220, delayMillis = 90)) with
            fadeOut(animationSpec = tween(90))
    },
    contentAlignment: Alignment = Alignment.TopStart,
    content: @Composable() AnimatedVisibilityScope.(targetState: S) -> Unit
)

targetState参数指定目标, transitionSpec参数用来指定动画行为。编写代码如下所示:

代码语言:javascript
复制
AnimatedContent(targetState = data,
    transitionSpec = {
        (scaleIn() with scaleOut()).using(SizeTransform(false))
    }) {
    Text(text = "数值:${data}")
}

 我们先来看,代码为什么可以这样写,transitionSpec参与是ContentTransform对象,我们来看ContentTransform的源码,如下所示:

代码语言:javascript
复制
@ExperimentalAnimationApi
class ContentTransform(
    val targetContentEnter: EnterTransition,
    val initialContentExit: ExitTransition,
    targetContentZIndex: Float = 0f,
    sizeTransform: SizeTransform? = SizeTransform()
)

可以看到参数指定了进入动画、退出动画 这一点与AnimatedVisibility的使用是相同的。

sizeTransForm参数定义了在初始内容与目标内容之间添加动画效果,进入、退出动画可以使用with函数来组合,sizeTransform参数提供了using扩展函数来使用,代码如下所示:

代码语言:javascript
复制
@ExperimentalAnimationApi
infix fun ContentTransform.using(sizeTransform: SizeTransform?) = this.apply {
    this.sizeTransform = sizeTransform
}

运行程序,效果图如下所示。

Crossfade与animateContentSize

animateContentSize可以在尺寸大小改变的时候添加动画,Crossfade是淡入淡出动画,可用于视图切换等操作。首先来看animateContentSize的使用。

animateContentSize

编写一个示例,包含一个Edittext和一个TextView,TextView中实时显示Edittext的输入内容,代码如下所示:

代码语言:javascript
复制
Column() {
    var message by remember { mutableStateOf("") }

    TextField(value = message, onValueChange = { message = it })

    Box(
        modifier = Modifier
            .background(Color.Red)
            .animateContentSize()
    ) {
        Text(text = message)
    }
}

 为了便于观察效果,我们这里设置背景为红色,运行程序,效果图如下所示。

有一种丝滑般的感觉,一起纵享丝滑吧~

Crossfade

Crossfade可用于两个视图间的切换动画,编写代码:按钮控制当前页面显示Screen1页面或Screen2页面,为了便于区分,两个页面分别设置背景为蓝色和绿色。具体代码此处就省略了。

页面切换部分代码如下所示:

代码语言:javascript
复制
var flag by remember {
    mutableStateOf(false)
}
Column() {
    Crossfade(targetState = flag, animationSpec = tween(3000)) {
        when (it) {
            false -> Screen1()
            true -> Screen2()
        }
    }
    Button(onClick = { flag = !flag }) {
        Text(text = "视图切换")
    }
}               

为了便于观察效果,此处为动画设置tween的间隔时间为3秒,运行程序,效果图如下所示:

Crossfade函数源码如下所示:

代码语言:javascript
复制
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun <T> Crossfade(
    targetState: T,
    modifier: Modifier = Modifier,
    animationSpec: FiniteAnimationSpec<Float> = tween(),
    content: @Composable (T) -> Unit
)            

 animationSpec参数是FiniteAnimationSpec类型的参数,实现类有TweenSpec、SpringSpec等,默认值是tween,tween是一个可配置的曲线动画,源码如下所示:

代码语言:javascript
复制
@Stable
fun <T> tween(
    durationMillis: Int = DefaultDurationMillis,
    delayMillis: Int = 0,
    easing: Easing = FastOutSlowInEasing
): TweenSpec<T> = TweenSpec(durationMillis, delayMillis, easing)           

我们也可以设置spring等效果,这里读者可自行尝试。

其他

除此之外,还有animate*AsState、rememberInfiniteTransition等低级别的动画API,更多用法,这里不再一一讲解了。回到刚开始前言的问题,如何实现 一个正在加载的动画呢?

这里我们使用rememberInfiniteTransition来定义一个无限加载的动画,并通过infiniteRepeatable来制定动画规范。最后一起来看一下,我的Compose开源项目中所实现的加载框的效果吧~

写在最后

近期越来越感觉,学无止境,需要学习的东西太多太多~ ,期待我们下篇文章 再见~

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-04-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 动画的种类
  • AnimationVisibility
  • AnimatedContent
  • Crossfade与animateContentSize
    • animateContentSize
      • Crossfade
      • 其他
      • 写在最后
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档