Android Compose Create A Custom Switch With Text Elements

In this post I will show you a custom composable switch I made. 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 to cumbersome for this little interaction.

I attempted to make 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

@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]
            )
        }
    }
}

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.


Comments

Leave a Reply

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