Compose 5 个简短动画,让您的应用脱颖而出

5 quick animations to make your Compose app stand out

浏览 5 个快速动画,让您的应用在短短几分钟内生动起来。

1. AnimatedVisibility()

下面使用简单的 if 语句来显示或隐藏文本。

为了提升 UI 效果,将不断变化的可见状态包装在 AnimatedVisibility 组合中,使得文本的显示或隐藏带有动画效果。

kotlin 复制代码
@Composable
public fun AnimatedVisibility(
    visible: Boolean,
    modifier: Modifier = Modifier,
    enter: EnterTransition = fadeIn() + expandIn(),
    exit: ExitTransition = shrinkOut() + fadeOut(),
    label: String = "AnimatedVisibility",
    content: @Composable() AnimatedVisibilityScope.() -> Unit,
) {
    val transition = updateTransition(visible, label)
    AnimatedVisibilityImpl(transition, { it }, modifier, enter, exit, content = content)
}

AnimatedVisibility 还有一系列不同的自定义选项。

2. Modifier.animateContentSize()

通过更改 Text 在屏幕上绘制的最大行数,单击文本时切换展开状态,

我们可以使用 Modifier 轻松修复这种跳跃状态。只需要将 animateContentSize() 添加到 Modifier 链中,即可获得即时平滑的变化。

kotlin 复制代码
public fun Modifier.animateContentSize(
    animationSpec: FiniteAnimationSpec<IntSize> =
        spring(
            stiffness = Spring.StiffnessMediumLow,
            visibilityThreshold = IntSize.VisibilityThreshold,
        ),
    finishedListener: ((initialValue: IntSize, targetValue: IntSize) -> Unit)? = null,
): Modifier =
    this.clipToBounds() then
        SizeAnimationModifierElement(animationSpec, Alignment.TopStart, finishedListener)

如果想让动画变得更有弹性,可以更改 animateContentSize() 修饰符以接受动画规范。 大多数动画 API 都提供设置动画规范的功能,可以使用它来定义动画如何发生。

下面给动画添加弹簧规范,将刚度 stiffness 设置为低,并添加少量的弹跳 dampingRatio 为 DampingRatioLowBouncy。我们可以看到动画拥有了弹跳的效果。

3. AnimatedContent()

通过选择多 Tab 中的选项,来切换不同的组合内容。此时的内容切换十分生硬,内容之间没有任何的平滑过渡。

将切换内容代码包装在 AnimatedContent 组合中,提供将要转换到的目标状态。现在不同组合项之间的切换具有淡入淡出和相互缩放的效果,比之前好多了。

kotlin 复制代码
@Composable
public fun <S> AnimatedContent(
    targetState: S,
    modifier: Modifier = Modifier,
    transitionSpec: AnimatedContentTransitionScope<S>.() -> ContentTransform = {
        (fadeIn(animationSpec = tween(220, delayMillis = 90)) +
                scaleIn(initialScale = 0.92f, animationSpec = tween(220, delayMillis = 90)))
            .togetherWith(fadeOut(animationSpec = tween(90)))
    },
    contentAlignment: Alignment = Alignment.TopStart,
    label: String = "AnimatedContent",
    contentKey: (targetState: S) -> Any? = { it },
    content: @Composable() AnimatedContentScope.(targetState: S) -> Unit,
) {
    val transition = updateTransition(targetState = targetState, label = label)
    transition.AnimatedContent(
        modifier,
        transitionSpec,
        contentAlignment,
        contentKey,
        content = content,
    )
}

通过更改 AnimatedContent 的过渡规范,我们可以自定义屏幕上出现的的新可组合项如何进入屏幕以及旧可组合项如何退出屏幕。

使用 slideIntoContainer 将新内容向上滑动进入,使用 slideOutOfContainer 将旧内容向下滑动退出。我们还通过 animationSpec 设置动画的持续时间和缓动效果。

4. animateFloatAsState()

进度条计算进度并更新展示,这样的变化十分生硬,缺少平滑过渡。

使用 animateFloatAsState() 动态计算进度,使得进度条的变化产生动画效果。

kotlin 复制代码
@Composable
public fun animateFloatAsState(
    targetValue: Float,
    animationSpec: AnimationSpec<Float> = defaultAnimation,
    visibilityThreshold: Float = 0.01f,
    label: String = "FloatAnimation",
    finishedListener: ((Float) -> Unit)? = null,
): State<Float> {
    val resolvedAnimSpec =
        if (animationSpec === defaultAnimation) {
            remember(visibilityThreshold) { spring(visibilityThreshold = visibilityThreshold) }
        } else {
            animationSpec
        }
    return animateValueAsState(
        targetValue,
        Float.VectorConverter,
        resolvedAnimSpec,
        visibilityThreshold,
        label,
        finishedListener,
    )
}

5. rememberInfiniteTransition() with Custom DrawScope drawing

实现自定义彩虹边框,颜色围绕着图像轮廓旋转。这里需要使用无限执行的动画。

  • 使用 rememberInfiniteTransition() 创建一个无限动画 InfiniteTransition 声明为 infiniteTransition
kotlin 复制代码
@Composable
public fun rememberInfiniteTransition(label: String = "InfiniteTransition"): InfiniteTransition {
    val infiniteTransition = remember { InfiniteTransition(label) }
    infiniteTransition.run()
    return infiniteTransition
}
  • 调用 infiniteTransition.animateFloat() 创建一个动态变化的 State 声明为 rotationAnimation
kotlin 复制代码
@Composable
public fun InfiniteTransition.animateFloat(
    initialValue: Float,
    targetValue: Float,
    animationSpec: InfiniteRepeatableSpec<Float>,
    label: String = "FloatAnimation",
): State<Float> =
    animateValue(initialValue, targetValue, Float.VectorConverter, animationSpec, label)
  • 在 Image 的 Modifier.drawBehind{} 代码块中调用 rotate() 方法,参数 degrees 角度传入上一步声明的 rotationAnimation
kotlin 复制代码
/** Draw into a [Canvas] behind the modified content. */
fun Modifier.drawBehind(onDraw: DrawScope.() -> Unit) = this then DrawBehindElement(onDraw)

inline fun DrawScope.rotate(degrees: Float, pivot: Offset = center, block: DrawScope.() -> Unit) =
    withTransform({ rotate(degrees, pivot) }, block)
  • 如此在绘制彩虹边框背景的时候,边框会不停地围绕图像旋转。

infiniteRepeatable()

创建一个无限重复动画规格

kotlin 复制代码
@Stable
public fun <T> infiniteRepeatable(
    animation: DurationBasedAnimationSpec<T>,
    repeatMode: RepeatMode = RepeatMode.Restart,
    initialStartOffset: StartOffset = StartOffset(0),
): InfiniteRepeatableSpec<T> = InfiniteRepeatableSpec(animation, repeatMode, initialStartOffset)
相关推荐
PenguinLetsGo2 小时前
你的App是否有出现过幽灵调用?
android
没有了遇见3 小时前
Android ViewPager2 嵌套 RecyclerView 滑动冲突解决方案
android
咖啡の猫3 小时前
Android开发-选择按钮
android·gitee
火柴就是我4 小时前
android 以maven的方式 引入本地的aar
android
过-眼-云-烟4 小时前
新版Android Studio能打包但无法run ‘app‘,编译通过后手机中没有安装,顶部一直转圈
android·ide·android studio
hedalei5 小时前
android14 硬键盘ESC改BACK按键返回无效问题
android·android14·esc·back按键
hcgeng5 小时前
android 如何判定底部导航栏显示时 不是键盘显示
android·底部导航·导航高度
和煦的春风5 小时前
性能案例分析 | Waiting for GPU completion
android·linux
用户2018792831675 小时前
ConcurrentHashMap:用 “社区超市” 故事讲透并发的设计哲学
android