一、高档别动画
1. 内容改动
动画 | 作用 | 其他阐明 |
---|---|---|
AnimatedVisibility | 显示/隐藏状况切换 | |
Crossfade | 布局切换 | |
AnimatedContent | 单个值改动 | 可组合项会在内容依据目标状况发生改动时,为内容增加动画作用。 |
animateContentSize | 为大小改动增加动画作用 | 为了保证流畅的动画,请必须将其放置在任何大小修饰符(如size 或defaultMinSize )前面,以保证animateContentSize 会将带动画作用的值的改动报告给布局。 |
1.1 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
)
- visible:内容是否可见
- modifier:修饰符
- enter:进入动画
- exit:退出动画
比如:
// 显示/隐藏状况
val inState = remember { mutableStateOf(true) }
AnimatedVisibility(
visible = inState.value,
// 设置淡入动画
enter = fadeIn() + expandVertically(),
// 设置淡出动画
exit = fadeOut() + shrinkVertically()
) {
Image(
painter = painterResource(id = R.mipmap.image_cat3),
contentDescription = null
)
}
以下是google为我们提供的几组自带的进入/退出动画作用,多个动画能够用+
进行组合运用。
EnterTransition(进入动画) | ExitTransition(退出动画) |
---|---|
fadeIn |
fadeOut |
slideIn |
slideOut |
slideInHorizontally |
slideOutHorizontally |
slideInVertically |
slideOutVertically |
scaleIn |
scaleOut |
expandIn |
shrinkOut |
expandHorizontally |
shrinkHorizontally |
expandVertically |
shrinkVertically |
1.2 Crossfade
由于此动画是用于在布局切换中履行,因此首要需求界说一组tag用于差异不同的布局,并将之传递给Crossfade
。先看看源码:
@Composable
fun <T> Crossfade(
targetState: T,
modifier: Modifier = Modifier,
animationSpec: FiniteAnimationSpec<Float> = tween(),
content: @Composable (T) -> Unit
)
- targetState:动画的触发器,表明动画履行的目标值,每次改动的时分都会触发动画。
- modifier:修饰符。
- animationSpec:配置动画。默以为
tween()
。
比如:
var currentPage by remember { mutableStateOf("A") }
Button(onClick = {
currentPage = if (currentPage == "A") "B" else "A"
}) {
Text(text = if (currentPage == "A") "切换到B" else "切换到A")
}
Crossfade(
targetState = currentPage,
// 设置切换时分的动画
animationSpec = tween(durationMillis = 1500)
) { screen ->
when (screen) {
"A" -> Box(
modifier = Modifier
.size(100.dp)
.background(color = Color.Cyan)
) { Text("Page A") }
"B" -> Box(
modifier = Modifier.size(100.dp)
) { Text("Page B") }
}
}
1.3 AnimatedContent
@Composable
fun <S> AnimatedContent(
targetState: S,
modifier: Modifier = Modifier,
transitionSpec: AnimatedContentScope<S>.() -> ContentTransform = { ...... },
contentAlignment: Alignment = Alignment.TopStart,
content: @Composable() AnimatedVisibilityScope.(targetState: S) -> Unit
)
- targetState:动画的触发器,表明动画履行的目标值,每次改动的时分都会触发动画。
- modifier:修饰符。
- transitionSpec:动画的履行规范。
- contentAlignment:动画的触发位置。默许是从布局的左上角进入/退出。
比如:
var count by remember { mutableStateOf(0) }
Button(onClick = { count++ }) {
Text("Add")
}
AnimatedContent(targetState = count) { targetCount ->
// Make sure to use `targetCount`, not `count`.
Text(text = "Count: $targetCount")
}
1.4 animateContentSize
fun Modifier.animateContentSize(
animationSpec: FiniteAnimationSpec<IntSize> = spring(),
finishedListener: ((initialValue: IntSize, targetValue: IntSize) -> Unit)? = null
)
- animationSpec:配置动画。默以为
spring()
。 - finishedListener:动画完结的监听。
比如:
var large by remember { mutableStateOf(true) }
Button(onClick = { large = !large }) {
Text(text = if (large) "变短" else "变长")
}
Box(
modifier = Modifier
.padding(top = 4.dp)
.background(Color.Blue)
// 敞开动画
.animateContentSize()
) {
Text(
text = "Hello",
modifier = Modifier.width(if (large) 100.dp else 50.dp)
)
}
2. 值改动
动画 | 作用 | 其他阐明 |
---|---|---|
animateXxxAsState | 为单个值改动增加动画 | |
updateTransition | 多个值跟着状况一同改动 | 通过自界说的一组状况来对一组值进行统一管理。 |
rememberInfiniteTransation | 多个值跟着状况一同改动 | 作用与updateTransition 类似。差异在于,此动画在一进入组合阶段就会开端不断重复地运转,除非被移除,否则不会中止。 |
2.1 animateXxxAsState
-
animateXxxAsState
十分简单,只需求提供一个最终的目标值,就会从当时值开端履举动画。 -
animateXxxAsState
支持的数据类型包括:Float
、Dp
、Size
、Offset
、Rect
、Int
、IntOffset
、IntSize
。
接下来,我们以Dp
为例:
@Composable
fun animateDpAsState(
targetValue: Dp,
animationSpec: AnimationSpec<Dp> = dpDefaultSpring,
finishedListener: ((Dp) -> Unit)? = null
)
- targetValue:动画的触发器,表明动画履行的目标值,每次改动的时分都会触发动画。
- animationSpec:配置动画。
- finishedListener:动画完结的监听。
看个比如:
@Composable
fun CustomAnimateContent() {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Top
) {
val size = remember { mutableStateOf(10) }
// 为尺寸增加动画
val sizeState by animateDpAsState(size.value.dp)
......
Box(
modifier = Modifier
.padding(top = 8.dp)
// 直接运用增加动画后的尺寸值
.size(size = sizeState)
.background(color = Color.Blue)
)
}
}
2.2 updateTransition
运用过程:
- 创立一组状况:引荐运用枚举类型来保证类型的安全。
- 运用
updateTransition
记住Transtion实例,并更新状况。 - 运用
animateXxx
函数来创立对应类型的子动画。 - 运用到组件特点上。
// 1. 界说一组状况
enum class UiState {
BIG_BLUE,
MIDDLE_RED,
SMALL_GREEN
}
@Composable
fun UpdateTransitionUi() {
// 2. 创立Transition对象
val state = remember { mutableStateOf(UiState.BIG_BLUE) }
val transition = updateTransition(targetState = state, label = "")
// 3. 创立动画
val size = transition.animateDp(label = "") {
when (it.value) {
UiState.BIG_BLUE -> 100.dp
UiState.MIDDLE_RED -> 70.dp
UiState.SMALL_GREEN -> 40.dp
}
}
val color = transition.animateColor(label = "") {
when (it.value) {
UiState.BIG_BLUE -> Color.Blue
UiState.MIDDLE_RED -> Color.Red
UiState.SMALL_GREEN -> Color.Green
}
}
......
Box(
modifier = Modifier
.padding(top = 4.dp)
// 4. 运用动画值
.size(size = size.value)
.background(color = color.value)
)
}
2.3 rememberInfiniteTransation
运用过程:
- 运用
rememberInfiniteTransition
办法结构一个InfiniteTransition
实例。 - 运用
InfiniteTransition
的animateXxx
办法创立子动画。 - 运用到组件特点上。
@Composable
fun InfiniteTransitionUi() {
// 1. 结构InfiniteTransition实例
val infiniteTransition = rememberInfiniteTransition()
// 2. 创立动画
val color by infiniteTransition.animateColor(
initialValue = Color.Red,
targetValue = Color.Green,
animationSpec = infiniteRepeatable(
animation = tween(1000, easing = LinearEasing),
repeatMode = RepeatMode.Reverse
)
)
Box(
Modifier
.width(200.dp)
.height(200.dp)
// 3. 运用动画值
.background(color)
)
}
二、低级别动画
1 Animatable
从命名就能够看出来,Animatable
是一个可履举动画的特点容器,里面能够放各种各样的数据。只要调用animatable.animateTo(newValue)
办法,即可使运用了该容器数据作为特点的组件履行相应的动画。
@Composable
private fun AnimatablePage() {
val size = remember { Animatable(100f) }
val sizeState = remember { mutableStateOf(size.value) }
LaunchedEffect(key1 = sizeState.value) {
size.animateTo(sizeState.value)
}
Column(modifier = Modifier.padding(16.dp)) {
FloatSetting(title = "圆心X轴偏移量", modifier = Modifier.height(40.dp), minNum = 100f, maxNum = 200f, interval = 20f, defNum = sizeState)
Canvas(
modifier = Modifier
.padding(top = 8.dp)
.size(size.value.dp)
) {
drawCircle(color = Color.Red)
}
Canvas(
modifier = Modifier
.padding(top = 8.dp)
.size(size.value.dp)
) {
drawRect(color = Color.Green)
}
}
}
2 Animation
Animation是一个用来描绘动画的接口,通过其源码我们能够看到它界说了一个动画的信息以及该动画在在履行过程中任一时间的状况。具体的后面再说。
留意看下面代码的注释:
- 1 界说了一个数据类型与动画在某一时间的值和速度的转换规则
- 2 界说了动画履行的时长
- 3 界说了动画履行的目标值
- 4 界说了动画是否是一个无限动画
- 5、6、7 一起界说了动画的过程
interface Animation<T, V : AnimationVector> {
/**
* 1. 将任意数据类型的值/速度转换为动画矢量的双向转换器
*/
val typeConverter: TwoWayConverter<T, V>
/**
* 2. 动画履行的时长(以纳秒为单位)
*/
@get:Suppress("MethodNameUnits")
val durationNanos: Long
/**
* 3. 动画履行的目标值
*/
val targetValue: T
/**
* 4. 是否是一个无限动画。
* 无限动画也不会自行完结,需求依赖于外部的举动才能中止。
* 例如,不确定的进度条,只有在从组成中删去时才会中止。
*/
val isInfinite: Boolean
/**
* 5. 回来给定播映时间动画的值。
*/
fun getValueFromNanos(playTimeNanos: Long): T
/**
* 6. 回来动画在给定播映时间的速度(以动画矢量形式)。
*/
fun getVelocityVectorFromNanos(playTimeNanos: Long): V
/**
* 7. 回来动画是否在给定播映时间完结。
*/
fun isFinishedFromNanos(playTimeNanos: Long): Boolean
}