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.
Leave a Reply