Home > database >  Initial animation android compose
Initial animation android compose

Time:05-11

I want to animate only once and I'm trying different options. I wanted to use animate*AsState but that doesn't work since you have to kind of trigger it by doing some kind of SideEffect with LaunchedEffect when entering in that screen like this:

@Composable
fun StartAnimation(width: Float = 0f) {
    var startAnimation by remember { mutableStateOf(false) }
    val widthAnimation = animateDpAsState(targetValue = if(startAnimation) width.dp else 0.dp, tween(600))
    Box(
        modifier = Modifier
            .padding(top = 30.dp)
            .padding(horizontal = 30.dp)
            .fillMaxWidth()
            .height(20.dp)
            .background(Color.Gray),
        contentAlignment = Alignment.CenterStart
    ) {
        Box(
            Modifier
                .background(Color.Black)
                .width(widthAnimation.value)
                .height(20.dp)
                .background(Color.Black)
        )
    }

    LaunchedEffect(key1 = true) {
        startAnimation = true
    }
}

Maybe there's a better way to do this and I'm missing it?

CodePudding user response:

Just create a custom fire-and-forget system. Works as a single-shot animator and can be spawned practically as many times as you like, in parallel.

@Composable
fun animateFloatAsState(
    initialValue: Float,
    targetValue: Float,
    delay: Long = 0,
    animationSpec: AnimationSpec<Float> = spring<Float>(),
    visibilityThreshold: Float = 0.01f,
    finishedListener: ((Float) -> Unit)? = null
): State<Float> {
    var trigger by remember { mutableStateOf(false) }
    return animateFloatAsState(
        targetValue = if (trigger) targetValue else initialValue,
        animationSpec = animationSpec,
        visibilityThreshold = visibilityThreshold,
        finishedListener = finishedListener
    ).also {
        LaunchedEffect(Unit) {
            delay(delay)
            trigger = true
        }
    }
}

This is for Float, but can as easily be translated to fit Dp. I think it is just replacing the word Float with Dp

CodePudding user response:

I don't think there is anything that will let you get rid of LaunchedEffect. But this might be better, at least you don't have to use that artificial variable:

val animatableWidth = remember { Animatable(0.dp, Dp.VectorConverter) }
LaunchedEffect(width) {
    animatableWidth.animateTo(width.dp, tween(600))
}
  • Related