iOS has Segmented controls like this.
I wanna have this in Android by using jetpack compose and I checked there is not build-in like this, and this UI in material 3 doesn't support jetpack compose now. What can I do? Totally customize the radio button? I know I can add the background and text and something, but how can I just hide check mark, make radio button looks like a button? Or there is something library I can use to use UI like Segmented controls? Can anyone give me some hints?
Asked
Active
Viewed 1,086 times
1

Gabriele Mariotti
- 320,139
- 94
- 887
- 841

Harvey Xie
- 81
- 4
2 Answers
5
You can use a Row
of OutlinedButton
applying an Offset
to avoid the double border.
Something like:
Row(
modifier = Modifier
.fillMaxWidth()
) {
val cornerRadius = 16.dp
var selectedIndex by remember { mutableStateOf(-1) }
itemsList.forEachIndexed { index, item ->
OutlinedButton(
onClick = { selectedIndex = index },
modifier = when (index) {
0 ->
Modifier
.offset(0.dp, 0.dp)
.zIndex(if (selectedIndex == index) 1f else 0f)
else ->
Modifier
.offset((-1 * index).dp, 0.dp)
.zIndex(if (selectedIndex == index) 1f else 0f)
},
shape = when (index) {
0 -> RoundedCornerShape(
topStart = cornerRadius,
topEnd = 0.dp,
bottomStart = cornerRadius,
bottomEnd = 0.dp
)
itemsList.size - 1 -> RoundedCornerShape(
topStart = 0.dp,
topEnd = cornerRadius,
bottomStart = 0.dp,
bottomEnd = cornerRadius
)
else -> RoundedCornerShape(
topStart = 0.dp,
topEnd = 0.dp,
bottomStart = 0.dp,
bottomEnd = 0.dp
)
},
border = BorderStroke(
1.dp, if (selectedIndex == index) {
Blue500
} else {
Blue500.copy(alpha = 0.75f)
}
),
colors = if (selectedIndex == index) {
ButtonDefaults.outlinedButtonColors(
containerColor = Blue500.copy(alpha = 0.1f),
contentColor = Blue500
)
} else {
ButtonDefaults.outlinedButtonColors(
containerColor = MaterialTheme.colorScheme.surface,
contentColor = Blue500
)
}
) {
Text("Button " + item)
}
}
}

Gabriele Mariotti
- 320,139
- 94
- 887
- 841
0
If you want to be exactly the same as the swiftUI component, you can use this code:
@Composable
fun SegmentedControl(
modifier: Modifier = Modifier,
items: List<String>,
defaultSelectedItemIndex: Int = 0,
useFixedWidth: Boolean = false,
itemWidth: Dp = 120.dp,
cornerRadius: Int = 24,
onItemSelection: (selectedItemIndex: Int) -> Unit
) {
val selectedIndex = remember { mutableStateOf(defaultSelectedItemIndex) }
val itemIndex = remember { mutableStateOf(defaultSelectedItemIndex) }
Card(
modifier = Modifier
.fillMaxWidth()
.height(38.dp),
colors = CardDefaults.cardColors(
containerColor = if (selectedIndex.value == itemIndex.value) {
MaterialTheme.colorScheme.background
} else {
MaterialTheme.colorScheme.secondary
}
),
shape = RoundedCornerShape(cornerRadius)
) {
Row(
modifier = modifier
.fillMaxWidth()
.background(MaterialTheme.colorScheme.secondary),
horizontalArrangement = Arrangement.Center
) {
items.forEachIndexed { index, item ->
itemIndex.value = index
Card(
modifier = modifier
.weight(1f)
.padding(2.dp),
onClick = {
selectedIndex.value = index
onItemSelection(selectedIndex.value)
},
colors = CardDefaults.cardColors(
containerColor = if (selectedIndex.value == index) {
MaterialTheme.colorScheme.background
} else {
MaterialTheme.colorScheme.secondary
},
contentColor = if (selectedIndex.value == index)
MaterialTheme.colorScheme.scrim
else
MaterialTheme.colorScheme.onSecondary
),
shape = when (index) {
0 -> RoundedCornerShape(
topStartPercent = cornerRadius,
topEndPercent = cornerRadius,
bottomStartPercent = cornerRadius,
bottomEndPercent = cornerRadius
)
items.size - 1 -> RoundedCornerShape(
topStartPercent = cornerRadius,
topEndPercent = cornerRadius,
bottomStartPercent = cornerRadius,
bottomEndPercent = cornerRadius
)
else -> RoundedCornerShape(
topStartPercent = 0,
topEndPercent = 0,
bottomStartPercent = 0,
bottomEndPercent = 0
)
},
) {
Box(modifier = modifier.fillMaxSize(), contentAlignment = Alignment.Center){
TitleText(
text = item,
style = LocalTextStyle.current.copy(
fontSize = 14.sp,
fontWeight = if (selectedIndex.value == index)
LocalTextStyle.current.fontWeight
else
FontWeight.Normal,
color = if (selectedIndex.value == index)
MaterialTheme.colorScheme.scrim
else
MaterialTheme.colorScheme.onSecondary
),
textAlign = TextAlign.Center,
)
}
}
}
}
}
}

Saeed Noshadi
- 829
- 12
- 34