jean
04/21/2022, 10:38 AManimateFloatAsState
with 2 iterations but when the animation ends, the size of the box jumps to the targetValue
Zach Klippenstein (he/him) [MOD]
04/21/2022, 5:08 PMjean
04/26/2022, 1:14 PMval size by animateDpAsState(
targetValue = if (selected) 16.dp else 8.dp,
animationSpec = repeatable(
iterations = 2,
animation = tween(durationMillis = 300),
repeatMode = RepeatMode.Reverse,
)
)
...
Box(
modifier = modifier
.size(size)
.clip(CircleShape)
.background(color)
)
the problem here is that the size of the box goes from 8 to 16 and back to 8 but then it jumps to 16 at the end of the animation.Zach Klippenstein (he/him) [MOD]
04/26/2022, 6:21 PMAnimatable
, e.g. something like:
val sizeAnimatable = remember { Animatable(…) }
LaunchedEffect(sizeAnimatable) {
snapshotFlow { selected }.collect { selected ->
// Launch allows the animation system to handle
// interruption itself, e.g. to preserve velocity.
launch {
if (selected) {
sizeAnimatable.animateTo(16.dp)
}
sizeAnimatable.animateTo(8.dp)
}
}
}
jean
04/26/2022, 6:23 PMAnimatable
coupled with the scale
attribute. I got inspiration from this thread https://kotlinlang.slack.com/archives/CJLTWPH7S/p1650534011825809 I managed to make it work but it’s far from pretty code, I still need to work on it@Composable
fun triggerScaleAnimation(): Float {
if (selected) {
LaunchedEffect(secretCircleState) {
animatedScale.animateTo(targetValue = 1.25f, animationSpec = tween(300))
animatedScale.animateTo(targetValue = 1f, animationSpec = tween(300))
}
}
return animatedScale.value
}
...
Box(
modifier = modifier
.size(8.dp)
.scale(animatedScale.value)
.clip(CircleShape)
.background(color)
)
triggerScaleAnimation()
Zach Klippenstein (he/him) [MOD]
04/26/2022, 6:28 PMtriggerScaleAnimation
should return a State<Float>
and instead of .scale(value)
do
.graphicsLayer {
scaleX = value
scaleY = value
}
jean
04/26/2022, 6:54 PMreturn derivedStateOf { animatedScale.value }
to return a State<Float>
but that makes the animation not work. How would you create the state object?@Composable
fun bounceAnimation(
selected: Boolean,
scaleFactor: Float,
durationMillis: Int,
): State<Float> {
val animatedScale = remember { Animatable(1f) }
if (selected) {
LaunchedEffect(selected) {
animatedScale.animateTo(targetValue = scaleFactor, animationSpec = tween(durationMillis / 2))
animatedScale.animateTo(targetValue = 1f, animationSpec = tween(durationMillis / 2))
}
}
return derivedStateOf { animatedScale.value }
}
and then using it like this
val scale by bounceAnimation(
selected = secretCircleState == SecretCircleState.SELECTED,
scaleFactor = 1.25f,
durationMillis = 300,
)
Box(
modifier = modifier
.size(8.dp)
.scale(scale)
.clip(CircleShape)
.background(color)
/*.graphicsLayer { if I use .graphicsLayer instead of .scale, it doesn't work
scaleX = scale
scaleY = scale
}*/
)
Zach Klippenstein (he/him) [MOD]
04/27/2022, 3:15 PManimatedScale.asState()
asState()
, but if you’re calling derivedStateOf
in a composable you need to wrap it in a remember
jean
04/27/2022, 3:51 PM