一、高档别动画

1. 内容改动

动画 作用 其他阐明
AnimatedVisibility 显示/隐藏状况切换
Crossfade 布局切换
AnimatedContent 单个值改动 可组合项会在内容依据目标状况发生改动时,为内容增加动画作用。
animateContentSize 为大小改动增加动画作用 为了保证流畅的动画,请必须将其放置在任何大小修饰符(如sizedefaultMinSize)前面,以保证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
10、Jetpack Compose 入门 --- 动画(一)
fadeOut
10、Jetpack Compose 入门 --- 动画(一)
slideIn
10、Jetpack Compose 入门 --- 动画(一)
slideOut
10、Jetpack Compose 入门 --- 动画(一)
slideInHorizontally
10、Jetpack Compose 入门 --- 动画(一)
slideOutHorizontally
10、Jetpack Compose 入门 --- 动画(一)
slideInVertically
10、Jetpack Compose 入门 --- 动画(一)
slideOutVertically
10、Jetpack Compose 入门 --- 动画(一)
scaleIn
10、Jetpack Compose 入门 --- 动画(一)
scaleOut
10、Jetpack Compose 入门 --- 动画(一)
expandIn
10、Jetpack Compose 入门 --- 动画(一)
shrinkOut
10、Jetpack Compose 入门 --- 动画(一)
expandHorizontally
10、Jetpack Compose 入门 --- 动画(一)
shrinkHorizontally
10、Jetpack Compose 入门 --- 动画(一)
expandVertically
10、Jetpack Compose 入门 --- 动画(一)
shrinkVertically
10、Jetpack Compose 入门 --- 动画(一)

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") }
  }
}

10、Jetpack Compose 入门 --- 动画(一)

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")
}

10、Jetpack Compose 入门 --- 动画(一)

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支持的数据类型包括:FloatDpSizeOffsetRectIntIntOffsetIntSize

接下来,我们以Dp为例:

@Composable
fun animateDpAsState(
    targetValue: Dp,
    animationSpec: AnimationSpec<Dp> = dpDefaultSpring,
    finishedListener: ((Dp) -> Unit)? = null
)
  • targetValue:动画的触发器,表明动画履行的目标值,每次改动的时分都会触发动画。
  • animationSpec:配置动画。
  • finishedListener:动画完结的监听。

看个比如:

10、Jetpack Compose 入门 --- 动画(一)

@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

运用过程:

  1. 创立一组状况:引荐运用枚举类型来保证类型的安全。
  2. 运用updateTransition记住Transtion实例,并更新状况。
  3. 运用animateXxx函数来创立对应类型的子动画。
  4. 运用到组件特点上。
// 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)
  )
}

10、Jetpack Compose 入门 --- 动画(一)

2.3 rememberInfiniteTransation

运用过程:

  1. 运用rememberInfiniteTransition办法结构一个InfiniteTransition实例。
  2. 运用InfiniteTransitionanimateXxx办法创立子动画。
  3. 运用到组件特点上。
@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)
  )
}

10、Jetpack Compose 入门 --- 动画(一)

二、低级别动画

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)
    }
  }
}

10、Jetpack Compose 入门 --- 动画(一)

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
}