Search code examples
androidkotlinandroid-jetpack-composeshow-hide

How to add/remove a button in Jetpack Compose while retaining its size


I have a button composable, and I want to hide/show it without affecting the surrounding composables' positions. For example, the following code is used to remove/add the button without making the text "Text" go up:

@Composable
fun Example(showButton: Boolean) {
    Column {
        Button(
            onClick = { /*TODO*/ },
            modifier = Modifier.alpha(if (showButton) 1f else 0f),
            enabled = showButton
        ) {
            Text(text = "Button")
        }
        Text(text = "Text")
    }
}

This code works perfectly, but if I add an infinite animation to the button, my code becomes this:

@Composable
fun Example(showButton: Boolean) {
    Column {
        if (showButton) {
            val infiniteTransition = rememberInfiniteTransition()
            val buttonScale by infiniteTransition.animateFloat(
                initialValue = 1f,
                targetValue = 1.005f,
                animationSpec = infiniteRepeatable(
                    animation = tween(durationMillis = 500, delayMillis = 0, easing = LinearEasing),
                    repeatMode = RepeatMode.Reverse
                )
            )
            Button(
                onClick = { /*TODO*/ },
                modifier = Modifier.graphicsLayer(scaleX = buttonScale, scaleY = buttonScale)
            ) {
                Text(text = "Button")
            }
        } else {
            Button(
                onClick = {},
                modifier = Modifier.alpha(0f),
                enabled = false
            ) {
                Text(text = "Button")
            }
        }
        Text(text = "Text")
    }
}

I opted to put infiniteTransition and buttonScale inside the if statement so the animation will not run if the button is removed, but now I have two buttons composables that I have to keep the same to maintain the same size so as not to affect the position of the surrounding elements (only the text in my example).

My question is: Is there a better way to solve this? I don't think my "solution" is a good practice.

Thanks.


Solution

  • You can control the showButton in Modifer.alpha as follows. Otherwise, the code will become very repetitive as it grows. You also need to set the enabled value for the Button. Otherwise, the button will be clickable even if it is not visible. This should also be taken into consideration

    @Composable
    fun Example(showButton: Boolean) {
        Column {
            val infiniteTransition = rememberInfiniteTransition()
            val buttonScale by infiniteTransition.animateFloat(
                initialValue = 1f,
                targetValue = 1.005f,
                animationSpec = infiniteRepeatable(
                    animation = tween(
                        durationMillis = 500,
                        delayMillis = 0,
                        easing = LinearEasing
                    ),
                    repeatMode = RepeatMode.Reverse
                )
            )
    
            Button(
                onClick = {},
                modifier = Modifier
                    .graphicsLayer(
                        scaleX = if (showButton) buttonScale else 1f,
                        scaleY = if (showButton) buttonScale else 1f
                    )
                    .alpha(if (showButton) 1f else 0f),
                enabled = showButton
    
            ) {
                Text(text = "Button")
            }
    
            Text(text = "Text")
        }
    }