一、简介
Jetpack Compose是Google推出的用于构建原生界面的新Android 工具包,它可简化并放慢 Android上的界面开发。Jetpack Compose是一个申明式的UI框架,随着该框架的推出,标记着Android 开始全面拥抱申明式UI开发。Jetpack Compose存在很多长处:代码更加简洁直观、利用开发效率显著晋升、Kotlin API性能直观、预览工具弱小等。
二、开发环境
为了取得更好的开发体验,笔者这里应用的是Android Studio Canary版本,这样能够无需配置一些设置和依赖。(下载地址)
关上工程,新建Empty Compose activity 模版,须要留神的是根目录下的build.gradle,相干的依赖com.android.tools.build和org.jetbrains.kotlin版本须要对应,否则可能呈现出错的情景,这里应用的是:
dependencies { classpath "com.android.tools.build:gradle:7.0.0-alpha15" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.30"}
这样就实现了我的项目的新建。
三、Jetpack Compose动画
Jetpack Compose提供了一些功能强大且可扩大的 API,可用于在利用界面中轻松实现各种动画成果。下文将会对Jetpack Compose Animations的罕用办法进行介绍。
3.1 状态驱动动画:State
Jetpack Compose动画是通过对状态的监听,即监听状态值的变动,使UI能实现自动更新。可组合函数能够应用 remember或者 mutableStateOf监听状态值的变动。如果状态值是不变的,remember函数会在每次重新组合中放弃该值;如果状态是可变的,它会在值发生变化的时候触发重组,mutableStateOf将失去一个MutableState对象,它是一个可察看类型。
这种重组是创立状态驱动动画的要害。利用重组,它们会在可组合组件的状态产生任何变动时被触发。Compose动画是由State驱动的,动画相干的API也较容易上手,能比拟容易发明出丑陋的申明式动画。
3.2 可见性动画: AnimatedVisibility
首先看下函数定义:
@ExperimentalAnimationApi@Composablefun AnimatedVisibility( visible: Boolean, modifier: Modifier = Modifier, enter: EnterTransition = fadeIn() + expandIn(), exit: ExitTransition = shrinkOut() + fadeOut(), initiallyVisible: Boolean = visible, content: @Composable () -> Unit) { AnimatedVisibilityImpl(visible, modifier, enter, exit, initiallyVisible, content)}
能够看出默认的动画是淡入放大、淡出膨胀,理论中通过传入不同函数实现各种动效。
随着可见值的变动,AnimatedVisibility可为其内容的呈现和隐没设置动画。如下代码,能够通过点击Button,管制图片的呈现和隐没。
@Composablefun AinmationDemo() { //AnimatedVisibility 可见动画 var visible by remember { mutableStateOf(true) } Column( Modifier .fillMaxWidth() .fillMaxHeight(), Arrangement.Top, Alignment.CenterHorizontally ) { Button( onClick = { visible = !visible } ) { Text(text = if (visible) "Hide" else "Show") } Spacer(Modifier.height(16.dp)) AnimatedVisibility( visible = visible, enter = slideInVertically() + fadeIn(), exit = slideOutVertically() + fadeOut() ) { Image( painter = painterResource(id = R.drawable.pikaqiu), contentDescription = null, Modifier.fillMaxSize() ) } }}
通过监听visible的变动,可实现图片的可见性动画,成果如小图所示;
3.3 布局大小动画:AnimateContentSize
先看下函数的定义:
fun Modifier.animateContentSize( animationSpec: FiniteAnimationSpec<IntSize> = spring(), finishedListener: ((initialValue: IntSize, targetValue: IntSize) -> Unit)? = null)
能够为布局大小动画设置动画速度和监听值。
由函数的定义能够看出这个函数实质上就Modefier的一个扩大函数。能够通过变量size监听状态变动实现布局大小的动画成果,代码如下:
//放大放大动画 animateContentSize var size by remember { mutableStateOf(Size(300F, 300F)) } Column( Modifier .fillMaxWidth() .fillMaxHeight(), Arrangement.Top, Alignment.CenterHorizontally ) { Spacer(Modifier.height(16.dp)) Button( onClick = { size = if (size.height == 300F) { Size(500F, 500F) } else { Size(300F, 300F) } } ) { Text(if (size.height == 300F) "Shrink" else "Expand") } Spacer(Modifier.height(16.dp)) Box( Modifier .animateContentSize() ) { Image( painter = painterResource(id = R.drawable.pikaqiu), contentDescription = null, Modifier .animateContentSize() .size(size = size.height.dp) ) }} //放大放大动画 animateContentSize var size by remember { mutableStateOf(Size(300F, 300F)) } Column( Modifier .fillMaxWidth() .fillMaxHeight(), Arrangement.Top, Alignment.CenterHorizontally ) { Spacer(Modifier.height(16.dp)) Button( onClick = { size = if (size.height == 300F) { Size(500F, 500F) } else { Size(300F, 300F) } } ) { Text(if (size.height == 300F) "Shrink" else "Expand") } Spacer(Modifier.height(16.dp)) Box( Modifier .animateContentSize() ) { Image( painter = painterResource(id = R.drawable.pikaqiu), contentDescription = null, Modifier .animateContentSize() .size(size = size.height.dp) ) }}
通过Button的点击,监听size值的变动,利用animateContentSize()实现动画成果,具体动效如下图所示:
3.4布局切换动画: Crossfade
Crossfade能够通过监听状态值的变动,应用淡入淡出的动画在两个布局之间增加动画成果,函数本身就是一个Composable,代码如下:
//Crossfade 淡入淡出动画 var fadeStatus by remember { mutableStateOf(true) } Column( Modifier .fillMaxWidth() .fillMaxHeight(), Arrangement.Top, Alignment.CenterHorizontally ) { Button( onClick = { fadeStatus = !fadeStatus } ) { Text(text = if (fadeStatus) "Fade In" else "Fade Out") } Spacer(Modifier.height(16.dp)) Crossfade(targetState = fadeStatus, animationSpec = tween(3000)) { screen -> when (screen) { true -> Image( painter = painterResource(id = R.drawable.pikaqiu), contentDescription = null, Modifier .animateContentSize() .size(300.dp) ) false -> Image( painter = painterResource(id = R.drawable.pikaqiu2), contentDescription = null, Modifier .animateContentSize() .size(300.dp) ) } } }
同样通过监听fadeStatus的值,实现布局切换的动画,具体的动效如图所示:
3.5单个值动画:animate*AsState
为单个值增加动画成果。只需提供完结值(或目标值),该 API 就会从以后值开始向指定值播放动画。
Jetpack Compose 提供了很多内置函数,能够为不同类型的数据制作动画,例如:animateColorAsState、animateDpAsState、animateOffsetAsState等,这里将介绍下animateFooAsState的应用,代码如下:
//animate*AsState 单个值增加动画 var transparent by remember { mutableStateOf(true) } val alpha: Float by animateFloatAsState(if (transparent) 1f else 0.5f) Column( Modifier .fillMaxWidth() .fillMaxHeight(), Arrangement.Top, Alignment.CenterHorizontally ) { Button( onClick = { transparent = !transparent } ) { Text(if (transparent) "Light" else "Dark") } Spacer(Modifier.height(16.dp)) Box { Image( painter = painterResource(id = R.drawable.pikaqiu), contentDescription = null, Modifier .animateContentSize() .graphicsLayer(alpha = alpha) .size(300.dp) ) }}
动画成果如下图所示:
3.6 组合动画:updateTransition
Transition 可同时追踪一个或多个动画,并在多个状态之间同步这些动画。具体的代码如下:
var imagePosition by remember { mutableStateOf(ImagePosition.TopLeft) } Column( Modifier .fillMaxWidth() .fillMaxHeight(), Arrangement.Top, Alignment.CenterHorizontally ) { Spacer(Modifier.height(16.dp)) val transition = updateTransition(targetState = imagePosition, label = "") val boxOffset by transition.animateOffset(label = "") { position -> when (position) { ImagePosition.TopLeft -> Offset(-60F, 0F) ImagePosition.BottomRight -> Offset(60F, 120F) ImagePosition.TopRight -> Offset(60F, 0F) ImagePosition.BottomLeft -> Offset(-60F, 120F) } } Button(onClick = { imagePosition = ChangePosition(imagePosition) }) { Text("Change position") } Box { Image( painter = painterResource(id = R.drawable.pikaqiu), contentDescription = null, Modifier .offset(boxOffset.x.dp, boxOffset.y.dp) .animateContentSize() .size(300.dp) ) }}
其中,ImagePosition、ChangePosition别离为定义的枚举类、自定义函数。
enum class ImagePosition { TopRight, TopLeft, BottomRight, BottomLeft}fun ChangePosition(position: ImagePosition) = when (position) { ImagePosition.TopLeft -> ImagePosition.BottomRight ImagePosition.BottomRight -> ImagePosition.TopRight ImagePosition.TopRight -> ImagePosition.BottomLeft ImagePosition.BottomLeft -> ImagePosition.TopLeft }
动画的如下图所示:
四、结语
Jetpack Compose 已将动画简化到只需在咱们的可组合函数中创立申明性代码的水平,只需编写心愿 UI 动画的形式,其余部分由 Compose 治理。最初,这也是是 Jetpack Compose 的次要指标:创立一个申明式 UI 工具包来减速利用程序开发并进步代码可读性和逻辑性。
Jetpack Compose提供的申明式UI工具包,能做到应用更少的代码实现更多的性能,且代码的可读性和逻辑性也大大提高了。
作者:vivo互联网游戏客户端团队-Ke Jie