Radio button 单选框
2026/1/31大约 3 分钟
Radio button 单选框
本文档覆盖 Jetpack Compose 中 RadioButton 的常用 API、使用模式(单选组)、可访问性提示、自定义样式与若干示例(垂直/水平列表、禁用、扩展点击区域)。
基本概念
RadioButton:表示一组选项中的单一选择项。通常在选中一个选项时会取消其它选项的选中状态。- 推荐模式是“状态提升”(state hoisting):父组件维护当前选中项的状态,子项只负责显示与触发
onClick。
核心 API(常用参数)
selected: Boolean:是否选中。onClick: () -> Unit:点击回调,通常用于更新父级的选中状态。enabled: Boolean:是否可交互(默认 true)。modifier: Modifier:用于布局、大小、点击目标扩展等。colors: RadioButtonColors:使用RadioButtonDefaults.colors(selectedColor = ..., unselectedColor = ..., disabledColor = ...)自定义颜色。interactionSource: MutableInteractionSource:用于监听交互状态(按下、悬停)。
可访问性
- 为非纯装饰性控件提供语义信息与
contentDescription(通常RadioButton与文本一同出现,文本会被屏幕阅读器读取)。 - 使用
Modifier.selectable(...)或Modifier.toggleable(...)来建立合适的语义与可访问性信息,例如:
Modifier.selectable(
selected = isSelected,
onClick = onSelect,
role = Role.RadioButton
)selectable 会自动将 role、state 等语义加入到组合中,提升无障碍体验。
示例:基础单个 RadioButton
@Composable
fun SimpleRadio() {
var selected by remember { mutableStateOf(false) }
RadioButton(selected = selected, onClick = { selected = !selected })
}示例:单选组(垂直列表)
推荐把选中状态提升到父组件,使用 LazyColumn 或 Column 渲染选项:
@Composable
fun RadioGroupExample(options: List<String>) {
var selectedIndex by remember { mutableStateOf(0) }
Column {
options.forEachIndexed { index, label ->
Row(
modifier = Modifier
.fillMaxWidth()
.selectable(
selected = (selectedIndex == index),
onClick = { selectedIndex = index },
role = Role.RadioButton
)
.padding(12.dp),
verticalAlignment = Alignment.CenterVertically
) {
RadioButton(selected = (selectedIndex == index), onClick = null)
Spacer(Modifier.width(8.dp))
Text(label)
}
}
}
}说明:将 onClick 放在 selectable 上(并使 RadioButton.onClick = null)可以避免事件重复,且 selectable 会带来更好的无障碍语义。
示例:水平单选组(用于工具栏等)
@Composable
fun HorizontalRadioGroup(options: List<String>) {
var selectedIndex by remember { mutableStateOf(0) }
Row(horizontalArrangement = Arrangement.spacedBy(12.dp), modifier = Modifier.padding(8.dp)) {
options.forEachIndexed { index, label ->
Row(
modifier = Modifier
.selectable(selected = selectedIndex == index, onClick = { selectedIndex = index }, role = Role.RadioButton),
verticalAlignment = Alignment.CenterVertically
) {
RadioButton(selected = selectedIndex == index, onClick = null)
Spacer(Modifier.width(4.dp))
Text(label)
}
}
}
}禁用与只读状态
RadioButton(selected = false, onClick = {}, enabled = false)禁用时 RadioButton 会呈现为不可交互的视觉样式。
自定义颜色与样式
@Composable
fun ColoredRadio() {
var selected by remember { mutableStateOf(true) }
RadioButton(
selected = selected,
onClick = { selected = !selected },
colors = RadioButtonDefaults.colors(
selectedColor = Color(0xFF1E88E5),
unselectedColor = Color.Gray,
disabledColor = Color.LightGray
)
)
}在列表中选择(带键盘/焦点支持)
对于需要键盘导航或焦点控制的场景,确保使用 Modifier.focusable() 并处理焦点请求。
组合控件:带说明的可点击行
把 RadioButton 与文本放在 Row 并使用 Modifier.selectable 是常见模式,能保证点击整个行都可选、并且无障碍描述正确。
无障碍与语义注意事项
- 使用
role = Role.RadioButton与selectable可以让屏幕阅读器识别该控件为单选控件。 - 提供清晰的文本标签代替只靠
contentDescription(屏幕阅读器优先读取显式文本)。
Material3 注意事项
- 在 Material3 中,
RadioButton的视觉样式和默认颜色可能与 Material2 不同,请参考androidx.compose.material3的实现与RadioButtonDefaults。
性能与最佳实践
- 状态提升:将选中状态放在父组件或 ViewModel 中,避免每个子项自己持有状态。
- 使用
LazyColumn展示大量选项以优化性能。 - 使用
remember/rememberSaveable保存必要状态以应对重组与配置变化。
小结(速查)
- 组件:
RadioButton - 关键参数:
selected、onClick、enabled、colors、modifier - 常用模式:
Modifier.selectable+Row(扩展点击区域并自动添加语义)、状态提升、列表单选 - 可访问性:为每个项提供可读标签并使用
role = Role.RadioButton
@Composable
fun RadioButtonComponents() {
val checkedIndex = remember {
mutableIntStateOf(-1)
}
val colorList = mutableListOf<String>(
"Red", "Green", "Yellow"
)
val bgColor = remember {
mutableStateOf(Color.White)
}
Column(
modifier = Modifier
.fillMaxSize()
.background(color = bgColor.value)
) {
Column {
colorList.forEachIndexed { index, item ->
Row(verticalAlignment = Alignment.CenterVertically) {
RadioButton(
selected = checkedIndex.intValue == index,
onClick = {
checkedIndex.intValue = index
when (index) {
0 -> bgColor.value = Color.Red
1 -> bgColor.value = Color.Green
2 -> bgColor.value = Color.Yellow
}
}
)
Text(text = item)
}
}
}
}
}