I have this code to get an infinite rotation animation:
@Composable
fun RotatingObject(rpm: Int) {
val infiniteTransition = rememberInfiniteTransition()
val rotation by infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = 360f,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 1000,
easing = LinearEasing
)
)
)
Surface(
Modifier
.size(100.dp)
.graphicsLayer { rotationZ = rotation},
color = Color.Gray
) {}
}
I want the rpm
parameter to define the number of revolutions per minute the object should make while spinning. I have tried setting durationMillis
to 60000 / rpm
but the speed stays the same after rpm
changes.
How can I get the speed to change after the initial composition?
Requirements
The rotation angle should not jump or jitter - it should always continually change based on the current rpm.
The solution should be friendly to animated rpm
values to allow for smoothly changing speed over time.
I would prefer a solution that doesn't cause avoidable recompositions.
Edit:
After trying countless different things, each of which had something wrong with it, I'm going to share the least wrong outcome.
@Composable
fun RotatingObject(rpm: Int) {
var rotation by remember { mutableStateOf(0f) }
val infiniteTransition = rememberInfiniteTransition()
val ticker by infiniteTransition.animateFloat(
initialValue = 0f,
targetValue = 360f,
animationSpec = infiniteRepeatable(
animation = tween(
durationMillis = 1000,
easing = LinearEasing
)
)
)
LaunchedEffect(ticker) {
rotation += 0.1f * rpm
}
Surface(
Modifier
.size(100.dp)
.graphicsLayer { rotationZ = rotation},
color = Color.Gray
) {}
}
I track the rotation value as state and manually change it inside a LaunchedEffect
. The relaunching of the effect is controlled by the infinite transition. This makes the rotation update at the expected frame rate. 0.1f * rpm
is the conversion of rpm to 'degrees per frame' at 60Hz.
So, this behaves as I want it to, however, in order to get here I made an assumption that I feel is not safe to make. This code requires that the effect is relaunched at a constant frequency of 60Hz. Since I didn't see this defined anywhere, this might just be the case on my system.
Also, if I do more operations inside the effect, it sometimes decides not to update the rotation at all, meaning that this is not a reliable way to do this. Therefore I feel that this is not a correct solution and I'm afraid it may not behave the same on different systems or at different times even. I currently have no choice but to use this, so if you have any ideas or suggestions, please share.