使用Android Jetpack Compose(可组合)实现图片源的动画更改。

6

我有一个矢量可绘制的图像,通过painter属性设置为Image的源。现在我想要更改源,但同时也要动画更改。所谓的动画效果并不是指使用路径数据进行变形动画,而是希望具有简单的淡入淡出效果。因此,一旦更改了源,我希望隐藏以前的图像,并显示当前的可绘制图像,并具有淡入淡出动画。

enter image description here

现在我正在使用一种解决方法,我使用了两个不同图像的源,并使用AnimatedVisibility来更改图像的可见性以匹配主题。是否有标准的方式可以动画更改源?这是我使用的hack,但我认为非常丑陋。
@OptIn(ExperimentalAnimationApi::class)
@Composable
fun AnimatedImage(modifier: Modifier, isLightTheme: Boolean, srcLight: Int = R.drawable.ic_sun, srcDark: Int = R.drawable.ic_moon) {

    val colors = LocalColors.current
    val (enter, exit) = remember {
        arrayListOf(
            fadeIn(animationSpec = tween(durationMillis = 1500)),
            fadeOut(animationSpec = tween(durationMillis = 500))
        )
    }

    AnimatedVisibility(
        visible = !isLightTheme,
        enter = enter as EnterTransition,
        exit = exit as ExitTransition
    ) {
        Image(
            painter = painterResource(id = srcDark), contentDescription = "",
            colorFilter = ColorFilter.tint(colors.secondsArrow),
            modifier = modifier
        )
    }

    AnimatedVisibility(
        visible = isLightTheme,
        enter = enter,
        exit = exit
    ) {
        Image(
            painter = painterResource(id = srcLight), contentDescription = "",
            colorFilter = ColorFilter.tint(colors.secondsArrow),
            modifier = modifier
        )
    }
}
1个回答

12

您可以使用基本的Crossfade动画:

Crossfade(
    flag,
    animationSpec = tween(1000)
) { targetState ->
    Image(
        painterResource(if (targetState) R.drawable.ic_redo else R.drawable.ic_undo),
        contentDescription = null,
        modifier = Modifier.background(Color.Black)
    )
}

如果你需要一个更复杂的动画效果,你可以使用AnimatedContent - 我的例子与双重AnimatedVisibility相等:

AnimatedContent(
    flag,
    transitionSpec = {
        fadeIn(animationSpec = tween(durationMillis = 1500)) with
                fadeOut(animationSpec = tween(durationMillis = 500))
    }
) { targetState ->
    Image(
        painterResource(if (targetState) R.drawable.ic_redo else R.drawable.ic_undo),
        contentDescription = null,
        modifier = Modifier.background(Color.Black)
    )
}

请注意,在两种情况下都需要使用传递给内容 lambda 的 targetState,因为在过渡期间,此 lambda 会被多次重组。
您可以在Compose动画文档中找到更多信息:documentation

非常好的答案,但如果painterResource的值是一个状态,即图像URL或资源是视图模型中的一部分,该怎么办?当viewModel中的状态改变时,动画如何知道它应该启动? - Jerome
1
如果传递给AnimatedContenttargetState值自上次重新组合以来发生了更改,则将启动@Jerome动画。您可以以多种方式在视图模型中存储状态 - 组成可变状态,FlowLiveData - 任何会在值更改时引起重新组合的东西。 - Phil Dukhov

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接