Need help on Jetpack Compose Animation - Kotlin

994 Views Asked by At

I am a newbie in android Kotlin development, it would be really appreciable, if someone can help me out. I already spent more than a week on the research of jetpack compose animation.

I have been trying to create a control where the circle has to given a pulsating animation and that needs to be controlled with various states or configuration. As a note - the animation is not only for a single circle, it has to be with multiple circle for different states.

I was able to implement the required animation with infiniteTransition, but that that doesn’t meet my requirement as it animates infinitely. I have given the code that I tried.

            @Composable
fun InfinitelyFlowingCircles() {
    val primaryColor = MaterialTheme.colors.primary
    val midCircle = primaryColor.copy(0.50f)

    DrawCircleOnCanvas(
        scale = scaleInfiniteTransition(initialValue = 0.5f, targetValue = 1f, durationMillis = 1000),
        color = midCircle,
        radiusRatio = 2f
    )
}

@Composable
private fun DrawCircleOnCanvas(
    scale: Float,
    color: Color,
    radiusRatio: Float
) {
    Canvas(
        modifier = Modifier
            .fillMaxSize()
            .graphicsLayer {
                scaleX = scale
                scaleY = scale
            }
    ) {
        val canvasWidth = size.width
        val canvasHeight = size.height
        drawCircle(
            color = color,
            center = Offset(
                x = canvasWidth / 2,
                y = canvasHeight / 2
            ),
            radius = size.minDimension / radiusRatio,
        )
    }
}

@Composable
private fun scaleInfiniteTransition(
    initialValue: Float = 0f,
    targetValue: Float,
    durationMillis: Int,
): Float {
    val infiniteTransition = rememberInfiniteTransition()
    val scale: Float by infiniteTransition.animateFloat(
        initialValue = initialValue,
        targetValue = targetValue,
        animationSpec =  infiniteRepeatable(
            animation = tween(durationMillis, easing = LinearEasing),
            repeatMode = RepeatMode.Reverse
        )
    )
    return scale
}

Also, I have tried a finite animation which works well, but I could find an option to get the finishListener in that animation so that I couldn't find a way to start the next animation. The code for the same has mentioned below.

   @Composable
fun UpdateTransition() {
    var circleState by remember {
        mutableStateOf(CircleState.Small)
    }

    val transition = updateTransition(
        targetState = circleState, label =
        "Circle Transition"
    )

    val color by transition.animateColor(label = "Color") { state ->
        when (state) {
            CircleState.Small -> Color.Blue
            CircleState.Large -> Color.Red
        }
    }

    val size by transition.animateDp(label = "Size") { state ->
        when (state) {
            CircleState.Small -> 100.dp
            CircleState.Large -> 200.dp
        }
    }
        Box(
            Modifier
                .clip(CircleShape)
                .size(size)
                .background(color)
                .clickable(
                    onClick = {
                        circleState = when (circleState) {
                            CircleState.Small -> CircleState.Large
                            CircleState.Large -> CircleState.Small
                        }
                    })
        ) {
        }
}
1

There are 1 best solutions below

4
On

You could use Animatable.

import androidx.compose.animation.core.Animatable
// Not the androidx.compose.animation.Animatable

@Composable
private fun MyUI() {

    val coroutineScope = rememberCoroutineScope()

    val scale = remember {
        Animatable(initialValue = 1f)
    }

    Box(
        modifier = Modifier
            .scale(scale = scale.value)
            .requiredSize(size = 40.dp)
            .background(color = Color.Red)
            .clickable {
                coroutineScope.launch {
                    scale.animateTo(
                        targetValue = 4f,
                        animationSpec = tween(durationMillis = 3000)
                    )
                    // after 3 seconds, this is executed
                    Log.d("ClickableBlock", "Animation Completed")
                }
            }
    )
}