I am trying to convert my View based code to Compose. I have a composable which takes an image (Painter) as argument and displays it using Image composable. What I want is that whenever the argument value changes, my Image should do a 360 degree rotation and the image should change while angle is approx. 180 degree (i.e. mid-way in the animation)
This is the composable I made.
@Composable
fun MyImage(displayImage: Painter) {
Image(
painter = displayImage,
contentDescription = null,
modifier = Modifier
.size(36.dp)
.clip(CircleShape)
)
}
Right now when the displayImage
changes, the new image is displayed immediately without any animation (obviously). How can I achieve the desired animation?
The code that I am trying to convert looks like this:
fun onImageChange(imageRes: Int) {
ObjectAnimator.ofFloat(imageView, View.ROTATION, 0f, 360f)
.apply {
addUpdateListener {
if (animatedFraction == 0.5f) {
imageView.setImageResource(imageRes)
}
}
start()
}
}
CodePudding user response:
It can be done using Animatable
.
Compose animations are based on coroutines, so you can wait for the animateTo
suspend function to complete, change the image and run another animation. Here's a basic example:
var flag by remember { mutableStateOf(true) }
val resourceId = remember(flag) { if (flag) R.drawable.profile else R.drawable.profile_inverted }
val rotation = remember { Animatable(0f) }
val scope = rememberCoroutineScope()
Column(Modifier.padding(30.dp)) {
Button(onClick = {
scope.launch {
rotation.animateTo(
targetValue = 180f,
animationSpec = tween(1000, easing = LinearEasing)
)
flag = !flag
rotation.animateTo(
targetValue = 360f,
animationSpec = tween(1000, easing = LinearEasing)
)
rotation.snapTo(0f)
}
}) {
Text("Rotate")
}
Image(
painterResource(id = resourceId),
contentDescription = null,
modifier = Modifier
.size(300.dp)
.rotate(rotation.value)
)
}
Output:
If you want to animate the changing images, you have to put two images in a Box
and animate the opacity of both as they rotate using one more Animatable
.