简体   繁体   中英

Android Jetpack Compose (Composable) Change Image source with animation

I have a vector drawable set as source via the painter attribute to an Image. Now I want to change the source, but also animate the change. By animation I don`t mean morphing animation with the path data, rather I want to have simple FadeIn, FadeOut effects. So once the source is changed I want the to hide the previous and show the current drawable with fade animation.

在此处输入图像描述

Now I am doing a workaround, I am using 2 Images with the sources of the two different images, and using AnimatedVisibility to change the visibility of the images, to match the theme. Is there a standard way of changing the source with animation?

Here is the hack I use, which is very ugly in my opinion

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

You can use basic Crossfade animation:

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

Or if you need a more complex one, you can use AnimatedContent - my example is equivalent to your double- 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)
    )
}

Note that in both cases it's required to use targetState passed in the content lambda, because this lambda is recomposed multiple times during transition.

You can find more info in Compose Animation documentation

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM