HarmonyOS ArkUI 选择组件实战:Checkbox 全选、Radio 组与 Toggle 三态
·
系列:鸿蒙 HarmonyOS 6.1 新特性实战 · 第 34 篇
选择类组件是表单开发的基础。ArkUI 提供了 Checkbox(多选框)、Radio(单选按钮)和 Toggle(开关)三类组件,各自适合不同场景。本篇重点演示全选/反选逻辑、Radio 分组和 Toggle 三种外观。
运行效果
初始状态,Checkbox 列表和 Radio 组:

全选状态和 Radio 选中效果:

一、Checkbox 全选模式
全选需要维护两个状态:列表项的选中数组和全选标志:
@State items: string[] = ['选项 A', '选项 B', '选项 C', '选项 D']
@State checked: boolean[] = [false, false, false, false]
@State allChecked: boolean = false
// 计算全选状态
get isAllChecked(): boolean {
return this.checked.every(v => v)
}
// 全选/取消全选
toggleAll(): void {
const val = !this.isAllChecked
this.checked = this.items.map(() => val)
this.allChecked = val
}
// 切换单项(必须创建新数组触发 @State 更新)
toggle(idx: number): void {
const arr = this.checked.slice()
arr[idx] = !arr[idx]
this.checked = arr
this.allChecked = arr.every(v => v)
}
关键:ArkTS 的 @State 数组必须赋值新数组才触发 UI 刷新,直接修改元素 this.checked[i] = true 不会更新界面。
// UI 渲染
Checkbox({ name: 'all', group: 'all' })
.select(this.allChecked)
.selectedColor('#0066ff')
.onChange(() => { this.toggleAll() })
ForEach(this.items, (item: string, idx: number) => {
Row({ space: 8 }) {
Checkbox({ name: item, group: 'items' })
.select(this.checked[idx])
.selectedColor('#0066ff')
.onChange(() => { this.toggle(idx) })
Text(item).fontSize(14)
}
})
二、Radio 单选组
Radio 按 group 属性自动互斥,不需要手动管理:
@State selectedFruit: string = 'apple'
// 三个 Radio 共享 group='fruit'
Row({ space: 8 }) {
Radio({ value: 'apple', group: 'fruit' })
.checked(this.selectedFruit === 'apple')
.selectedColor('#0066ff')
.onChange((isOn: boolean) => { if (isOn) this.selectedFruit = 'apple' })
Text('苹果').fontSize(14)
}
Row({ space: 8 }) {
Radio({ value: 'banana', group: 'fruit' })
.checked(this.selectedFruit === 'banana')
.selectedColor('#0066ff')
.onChange((isOn: boolean) => { if (isOn) this.selectedFruit = 'banana' })
Text('香蕉').fontSize(14)
}
最佳实践:用 ForEach 遍历选项数组,避免重复代码:
private fruits: string[] = ['苹果', '香蕉', '橙子']
private fruitValues: string[] = ['apple', 'banana', 'orange']
ForEach(this.fruits, (fruit: string, idx: number) => {
Row({ space: 8 }) {
Radio({ value: this.fruitValues[idx], group: 'fruit' })
.checked(this.selectedFruit === this.fruitValues[idx])
.onChange((isOn: boolean) => {
if (isOn) this.selectedFruit = this.fruitValues[idx]
})
Text(fruit).fontSize(14)
}
})
三、Toggle 三种外观
Toggle 的 type 属性控制外观形式:
// Switch:开关(最常用,用于设置项)
Toggle({ type: ToggleType.Switch, isOn: this.switchOn })
.selectedColor('#0066ff')
.onChange((val: boolean) => { this.switchOn = val })
// Button:按钮式开关(用于功能切换)
Toggle({ type: ToggleType.Button, isOn: this.btnOn }) {
Text('蓝牙').fontSize(14)
.fontColor(this.btnOn ? '#fff' : '#333')
}
.selectedColor('#0066ff')
.onChange((val: boolean) => { this.btnOn = val })
// Checkbox:复选框样式
Toggle({ type: ToggleType.Checkbox, isOn: this.cbOn })
.selectedColor('#0066ff')
.onChange((val: boolean) => { this.cbOn = val })
完整代码
@Entry
@Component
struct Index {
@State items: string[] = ['选项 A', '选项 B', '选项 C', '选项 D']
@State checked: boolean[] = [false, false, false, false]
@State allChecked: boolean = false
@State selectedFruit: string = 'apple'
@State switchOn: boolean = true
@State btnOn: boolean = false
@State cbOn: boolean = false
private fruits: string[] = ['苹果', '香蕉', '橙子', '葡萄']
private fruitValues: string[] = ['apple', 'banana', 'orange', 'grape']
toggleAll(): void {
const val = !this.checked.every(v => v)
this.checked = this.items.map(() => val)
this.allChecked = val
}
toggle(idx: number): void {
const arr = this.checked.slice()
arr[idx] = !arr[idx]
this.checked = arr
this.allChecked = arr.every(v => v)
}
build() {
Scroll() {
Column({ space: 20 }) {
Text('Checkbox / Radio / Toggle 选择组件')
.fontSize(21).fontWeight(FontWeight.Bold).fontColor('#1a1a1a')
// Checkbox 全选
Column({ space: 10 }) {
Text('一、Checkbox 全选模式').fontSize(15).fontWeight(FontWeight.Bold).fontColor('#333')
Row({ space: 8 }) {
Checkbox({ name: 'all', group: 'all' })
.select(this.allChecked)
.selectedColor('#0066ff')
.onChange(() => { this.toggleAll() })
Text('全选').fontSize(14).fontWeight(FontWeight.Medium).fontColor('#333')
}
.alignItems(VerticalAlign.Center)
ForEach(this.items, (item: string, idx: number) => {
Row({ space: 8 }) {
Checkbox({ name: item, group: 'items' })
.select(this.checked[idx])
.selectedColor('#0066ff')
.onChange(() => { this.toggle(idx) })
Text(item).fontSize(14).fontColor('#555')
}
.alignItems(VerticalAlign.Center)
})
Text('已选:' + this.items.filter((_: string, i: number) => this.checked[i]).join('、'))
.fontSize(13).fontColor('#0066ff')
}
.padding(12).backgroundColor('#fff').borderRadius(8).width('100%')
.border({ width: 1, color: '#e0e0e0' }).alignItems(HorizontalAlign.Start)
// Radio
Column({ space: 10 }) {
Text('二、Radio 单选组').fontSize(15).fontWeight(FontWeight.Bold).fontColor('#333')
ForEach(this.fruits, (fruit: string, idx: number) => {
Row({ space: 8 }) {
Radio({ value: this.fruitValues[idx], group: 'fruit' })
.checked(this.selectedFruit === this.fruitValues[idx])
.selectedColor('#0066ff')
.onChange((isOn: boolean) => {
if (isOn) { this.selectedFruit = this.fruitValues[idx] }
})
Text(fruit).fontSize(14).fontColor('#555')
}
.alignItems(VerticalAlign.Center)
})
Text('已选:' + this.fruits[this.fruitValues.indexOf(this.selectedFruit)])
.fontSize(13).fontColor('#0066ff')
}
.padding(12).backgroundColor('#fff').borderRadius(8).width('100%')
.border({ width: 1, color: '#e0e0e0' }).alignItems(HorizontalAlign.Start)
// Toggle
Column({ space: 10 }) {
Text('三、Toggle 三种外观').fontSize(15).fontWeight(FontWeight.Bold).fontColor('#333')
Row({ space: 16 }) {
Text('Switch:').fontSize(13).fontColor('#555').width(70)
Toggle({ type: ToggleType.Switch, isOn: this.switchOn })
.selectedColor('#0066ff')
.onChange((val: boolean) => { this.switchOn = val })
Text(this.switchOn ? '开' : '关').fontSize(13)
.fontColor(this.switchOn ? '#0066ff' : '#aaa')
}
.alignItems(VerticalAlign.Center)
Row({ space: 16 }) {
Text('Button:').fontSize(13).fontColor('#555').width(70)
Toggle({ type: ToggleType.Button, isOn: this.btnOn }) {
Text('蓝牙').fontSize(13)
.fontColor(this.btnOn ? '#fff' : '#333').padding({ left: 12, right: 12 })
}
.selectedColor('#0066ff')
.onChange((val: boolean) => { this.btnOn = val })
}
.alignItems(VerticalAlign.Center)
Row({ space: 16 }) {
Text('Checkbox:').fontSize(13).fontColor('#555').width(70)
Toggle({ type: ToggleType.Checkbox, isOn: this.cbOn })
.selectedColor('#0066ff')
.onChange((val: boolean) => { this.cbOn = val })
}
.alignItems(VerticalAlign.Center)
}
.padding(12).backgroundColor('#fff').borderRadius(8).width('100%')
.border({ width: 1, color: '#e0e0e0' }).alignItems(HorizontalAlign.Start)
}
.padding(20).width('100%')
}
.width('100%').height('100%').backgroundColor('#f5f5f5')
}
}
API 速查
| 组件/属性 | 说明 |
|---|---|
Checkbox({ name, group }) |
复选框,同 group 的 Checkbox 联动 |
.select(bool) |
设置选中状态 |
.selectedColor('#0066ff') |
选中颜色 |
Radio({ value, group }) |
单选,同 group 自动互斥 |
.checked(bool) |
初始选中状态 |
Toggle({ type, isOn }) |
开关,type 为 Switch/Button/Checkbox |
.onChange((val)=>{}) |
状态变化回调 |
小结
@State数组更新要赋新引用:this.checked = arr.slice()而不是直接this.checked[i] = val- Radio 靠 group 自动互斥:不需要手动取消其他 Radio
- Toggle Switch 是设置页首选:右对齐 Toggle.Switch + 左侧说明文字,是 HarmonyOS 设置页的标准模式
- 全选逻辑:
every()判断,整体赋值:不要遍历修改,要新数组整体赋值
上一篇:Button 组件深度解析 | 下一篇:Slider 与 Rating 滑动评分组件
更多推荐



所有评论(0)