Create An Animated Android Switch To Toggle UI Composables
In this post I will show you how I created a custom test switch for Android Compose.

In this post I will show you a custom animated android switch I made to toggle between main composable UI elements. The switch holds text elements instead of the thumb element.

I made this for my project that will either display a login screen or a registration screen to the user. I didn't want to implement a Navigation element because after the user chooses and follows through with either form, I will open a new Intent. A Navigation element would have been too cumbersome for this little interaction.

I made this so it could work universally for a variety of applications. There is also a callback to capture when the user changes the state.

Code

TextSwitch

This is the animated Android switch. It is created by using a Row composable inside of another Row composable. This was the quickest to implement using the layout position modifiers. Inside the child Row are the two Text composables. The state is triggered with a simple switching boolean that is created in the MainActivity.

@Composable
fun TextSwitch(
    textNames: List<String>,
    primaryColor: Color,
    backgroundColor: Color,
    switchPadding: Float,
    callback: (Boolean) -> Unit
) {

    var toggleState by remember { mutableStateOf(true) }
    var myWidth by remember { mutableStateOf(0f) }
    val toggleAnim by animateFloatAsState(if (toggleState) 0f + switchPadding else myWidth / 2 - switchPadding)

    Row(
        modifier = Modifier
            .fillMaxWidth()
            .padding(20.dp)
            .clickable {
                toggleState = !toggleState
                callback(toggleState)
            },
        horizontalArrangement = Arrangement.Center
    ) {

        Row(
            modifier = Modifier
                .fillMaxWidth()
                .onGloballyPositioned {
                    myWidth = it.size.width.toFloat()
                }
                .background(
                    color = backgroundColor,
                    shape = RoundedCornerShape(64f)
                )
                .drawBehind {
                    drawRoundRect(
                        color = primaryColor,
                        topLeft = Offset(toggleAnim, 0f + switchPadding),
                        size = Size(myWidth / 2, size.height - switchPadding * 2),
                        cornerRadius = CornerRadius(64f, 64f)
                    )
                },
            horizontalArrangement = Arrangement.SpaceAround
        ) {
            Text(
                modifier = Modifier
                    .padding(20.dp),
                color = if (toggleState) Color.White else primaryColor,
                text = textNames[0]
            )
            Text(
                modifier = Modifier
                    .padding(20.dp),
                color = if (!toggleState) Color.White else primaryColor,
                text = textNames[1]
            )
        }
    }
}

MainActivity

Then to implement it, add to your MainActivity

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            SampleLoginRegisterToggleTheme {
                Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
                    Column(
                        modifier = Modifier
                            .fillMaxSize()
                            .padding(innerPadding),
                        verticalArrangement = Arrangement.Center,
                        horizontalAlignment = Alignment.CenterHorizontally
                    ) {

                        var textSwitchToggle by remember { mutableStateOf(true) }
                        val textNames = listOf("Login", "Register")
                        TextSwitch(
                            textNames = textNames,
                            primaryColor = MaterialTheme.colorScheme.primary,
                            backgroundColor = Color.Gray.copy(alpha = 0.25f),
                            switchPadding = 5f
                        ) { isLoginSelected ->
                            textSwitchToggle = isLoginSelected
                        }
                        Text(text = if (textSwitchToggle) textNames[0] else textNames[1])
                    }

                }
            }
        }
    }
}

Hope this was useful.

Leave a Reply

Your email address will not be published. Required fields are marked *