14.ArkUI Radio的介绍和使用

ArkUI Radio 组件介绍与使用指南

什么是 Radio 组件?

Radio(单选框)是 ArkUI 中的单选按钮组件,允许用户从一组互斥的选项中选择一个选项。它通常用于表单、设置界面等需要用户做出单一选择的场景。

Radio 的核心特性

  1. 单选功能:一组 Radio 中只能选择一个
  2. 状态管理:支持选中和未选中两种状态
  3. 标签支持:可以添加文字标签
  4. 自定义样式:可修改颜色、大小等外观属性
  5. 事件响应:支持选择状态变化的回调

基本使用方法

单个 Radio 使用

typescript 复制代码
@Entry
@Component
struct SingleRadioExample {
  @State isChecked: boolean = false

  build() {
    Column() {
      Radio({ value: 'option1', group: 'group1' })
        .checked(this.isChecked)
        .onChange((isChecked: boolean) => {
          this.isChecked = isChecked
          console.log('Radio状态变化:', isChecked)
        })
      
      Text(this.isChecked ? '已选中' : '未选中')
        .margin({ top: 10 })
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

Radio 组使用

typescript 复制代码
@Entry
@Component
struct RadioGroupExample {
  @State selectedValue: string = 'option1'
  
  private options = [
    { value: 'option1', label: '选项1' },
    { value: 'option2', label: '选项2' },
    { value: 'option3', label: '选项3' }
  ]

  build() {
    Column() {
      Text('当前选择: ' + this.selectedValue)
        .fontSize(20)
        .margin({ bottom: 20 })
      
      ForEach(this.options, (item) => {
        Row() {
          Radio({ value: item.value, group: 'myGroup' })
            .checked(this.selectedValue === item.value)
            .onChange((checked: boolean) => {
              if (checked) {
                this.selectedValue = item.value
              }
            })
          
          Text(item.label)
            .margin({ left: 10 })
        }
        .margin({ bottom: 10 })
      })
    }
    .width('100%')
    .height('100%')
    .padding(20)
  }
}

高级用法

自定义样式

typescript 复制代码
@Entry
@Component
struct StyledRadioExample {
  @State selectedColor: string = 'red'
  
  private colors = [
    { value: 'red', label: '红色' },
    { value: 'green', label: '绿色' },
    { value: 'blue', label: '蓝色' }
  ]

  build() {
    Column() {
      Text('选择你喜欢的颜色:')
        .fontSize(18)
        .margin({ bottom: 20 })
      
      ForEach(this.colors, (color) => {
        Row() {
          Radio({ value: color.value, group: 'colorGroup' })
            .checked(this.selectedColor === color.value)
            .onChange((checked: boolean) => {
              if (checked) {
                this.selectedColor = color.value
              }
            })
            .radioStyle({
              pointColor: Color.White,
              activeColor: color.value,
              inactiveColor: '#dddddd',
              size: 20,
              strokeWidth: 2
            })
          
          Text(color.label)
            .fontColor(color.value)
            .margin({ left: 10 })
        }
        .margin({ bottom: 15 })
      })
      
      Divider()
        .margin({ vertical: 20 })
      
      Text('当前选择: ' + this.selectedColor)
        .fontSize(16)
        .fontColor(this.selectedColor)
    }
    .width('100%')
    .height('100%')
    .padding(20)
  }
}

与 List 结合使用

typescript 复制代码
@Entry
@Component
struct RadioListExample {
  @State selectedId: number = 1
  
  private items = [
    { id: 1, name: 'iPhone 15', price: '¥7999' },
    { id: 2, name: '华为 Mate 60', price: '¥6499' },
    { id: 3, name: '小米 14', price: '¥3999' },
    { id: 4, name: '三星 S23', price: '¥5699' }
  ]

  build() {
    Column() {
      Text('请选择您想购买的商品:')
        .fontSize(18)
        .margin({ bottom: 15 })
      
      List({ space: 10 }) {
        ForEach(this.items, (item) => {
          ListItem() {
            Row() {
              Radio({ value: item.id.toString(), group: 'productGroup' })
                .checked(this.selectedId === item.id)
                .onChange((checked: boolean) => {
                  if (checked) {
                    this.selectedId = item.id
                  }
                })
                .margin({ right: 15 })
              
              Column() {
                Text(item.name)
                  .fontSize(16)
                  .fontWeight(FontWeight.Bold)
                
                Text(item.price)
                  .fontSize(14)
                  .fontColor('#ff5500')
              }
              .layoutWeight(1)
            }
            .width('100%')
            .padding(15)
            .borderRadius(8)
            .backgroundColor(this.selectedId === item.id ? '#f0f9ff' : '#ffffff')
          }
        })
      }
      .width('100%')
      .layoutWeight(1)
      
      Button('确认选择', { type: ButtonType.Capsule })
        .width('80%')
        .height(40)
        .margin({ top: 20 })
        .backgroundColor('#1890ff')
        .enabled(this.selectedId !== 0)
        .onClick(() => {
          const selectedItem = this.items.find(item => item.id === this.selectedId)
          AlertDialog.show({
            title: '确认选择',
            message: `您已选择: ${selectedItem?.name}
价格: ${selectedItem?.price}`,
            confirm: {
              value: '确定',
              action: () => {
                console.log('用户确认选择')
              }
            }
          })
        })
    }
    .width('100%')
    .height('100%')
    .padding(20)
  }
}

实际应用示例

设置页面单选

typescript 复制代码
@Entry
@Component
struct SettingsPage {
  @State fontSize: string = 'medium'
  @State theme: string = 'light'
  @State notification: boolean = true

  build() {
    Navigation() {
      Scroll() {
        Column() {
          // 字体大小设置
          Text('字体大小')
            .fontSize(18)
            .margin({ top: 20, bottom: 10 })
          
          Row() {
            Radio({ value: 'small', group: 'fontGroup' })
              .checked(this.fontSize === 'small')
              .onChange((checked) => checked && (this.fontSize = 'small'))
              .radioStyle({ size: 16 })
            
            Text('小')
              .fontSize(14)
              .margin({ left: 5, right: 20 })
            
            Radio({ value: 'medium', group: 'fontGroup' })
              .checked(this.fontSize === 'medium')
              .onChange((checked) => checked && (this.fontSize = 'medium'))
              .radioStyle({ size: 18 })
            
            Text('中')
              .fontSize(16)
              .margin({ left: 5, right: 20 })
            
            Radio({ value: 'large', group: 'fontGroup' })
              .checked(this.fontSize === 'large')
              .onChange((checked) => checked && (this.fontSize = 'large'))
              .radioStyle({ size: 20 })
            
            Text('大')
              .fontSize(18)
              .margin({ left: 5 })
          }
          .margin({ bottom: 20 })
          
          Divider()
          
          // 主题设置
          Text('主题模式')
            .fontSize(18)
            .margin({ top: 20, bottom: 10 })
          
          Column() {
            Radio({ value: 'light', group: 'themeGroup' })
              .checked(this.theme === 'light')
              .onChange((checked) => checked && (this.theme = 'light'))
              .width('100%')
              .height(40)
            
            Radio({ value: 'dark', group: 'themeGroup' })
              .checked(this.theme === 'dark')
              .onChange((checked) => checked && (this.theme = 'dark'))
              .width('100%')
              .height(40)
            
            Radio({ value: 'auto', group: 'themeGroup' })
              .checked(this.theme === 'auto')
              .onChange((checked) => checked && (this.theme = 'auto'))
              .width('100%')
              .height(40)
          }
          .margin({ bottom: 20 })
          
          Divider()
          
          // 通知设置
          Text('通知设置')
            .fontSize(18)
            .margin({ top: 20, bottom: 10 })
          
          Row() {
            Radio({ value: 'enable', group: 'notifyGroup' })
              .checked(this.notification)
              .onChange((checked) => this.notification = checked)
            
            Text('启用通知')
              .margin({ left: 10 })
          }
          
          Row() {
            Radio({ value: 'disable', group: 'notifyGroup' })
              .checked(!this.notification)
              .onChange((checked) => this.notification = !checked)
            
            Text('禁用通知')
              .margin({ left: 10 })
          }
          .margin({ top: 10 })
        }
        .padding(20)
      }
    }
    .title('设置')
  }
}

问卷调查

typescript 复制代码
@Entry
@Component
struct SurveyPage {
  @State answers: { [key: string]: string } = {
    q1: '',
    q2: '',
    q3: ''
  }

  private questions = [
    {
      id: 'q1',
      text: '1. 您如何评价我们的产品质量?',
      options: [
        { value: 'excellent', label: '非常好' },
        { value: 'good', label: '好' },
        { value: 'average', label: '一般' },
        { value: 'poor', label: '差' }
      ]
    },
    {
      id: 'q2',
      text: '2. 您对我们的客户服务满意吗?',
      options: [
        { value: 'very_satisfied', label: '非常满意' },
        { value: 'satisfied', label: '满意' },
        { value: 'neutral', label: '一般' },
        { value: 'dissatisfied', label: '不满意' }
      ]
    },
    {
      id: 'q3',
      text: '3. 您会向朋友推荐我们的产品吗?',
      options: [
        { value: 'definitely', label: '一定会' },
        { value: 'probably', label: '可能会' },
        { value: 'not_sure', label: '不确定' },
        { value: 'no', label: '不会' }
      ]
    }
  ]

  build() {
    Navigation() {
      Scroll() {
        Column() {
          Text('客户满意度调查')
            .fontSize(22)
            .fontWeight(FontWeight.Bold)
            .margin({ bottom: 30 })
          
          ForEach(this.questions, (question) => {
            Column() {
              Text(question.text)
                .fontSize(18)
                .margin({ bottom: 15 })
              
              Column() {
                ForEach(question.options, (option) => {
                  Row() {
                    Radio({ value: option.value, group: question.id })
                      .checked(this.answers[question.id] === option.value)
                      .onChange((checked) => {
                        if (checked) {
                          this.answers[question.id] = option.value
                        }
                      })
                    
                    Text(option.label)
                      .margin({ left: 10 })
                  }
                  .margin({ bottom: 8 })
                })
              }
              .margin({ left: 20, bottom: 30 })
              
              Divider()
            }
          })
          
          Button('提交问卷', { type: ButtonType.Capsule })
            .width('80%')
            .height(45)
            .margin({ top: 30 })
            .backgroundColor('#1890ff')
            .enabled(Object.values(this.answers).every(answer => answer !== ''))
            .onClick(() => {
              console.log('提交的答案:', this.answers)
              AlertDialog.show({
                title: '提交成功',
                message: '感谢您参与我们的调查!',
                confirm: {
                  value: '确定',
                  action: () => {
                    router.back()
                  }
                }
              })
            })
        }
        .padding(20)
      }
    }
    .title('问卷调查')
  }
}

注意事项

  1. 分组使用:同一组的 Radio 组件会自动互斥,确保使用相同的 group 名称
  2. 默认值设置:建议为 Radio 组设置默认选中项,避免用户未选择的情况
  3. 无障碍支持:为 Radio 添加有意义的标签,方便屏幕阅读器识别
  4. 性能考虑:当 Radio 数量很多时,考虑使用虚拟
相关推荐
搞瓶可乐4 天前
鸿蒙ArkUI实战之组件;Text组件,Image组件,Button组件,Span组件和TextInput组件的使用场景及使用方法
华为·harmonyos·鸿蒙系统·arkui·组件化开发·基础组件使用
搞瓶可乐4 天前
鸿蒙ArkUI实战之TextArea组件、RichEditor组件、RichText组件、Search组件的使用
华为·harmonyos·arkui·搜索框·富文本组件·富文本输入框·鸿蒙原生api
搞瓶可乐5 天前
鸿蒙ArkUI之布局实战,线性布局(Column,Row)、弹性布局(Flex)、层叠布局(Stack),详细用法
前端·harmonyos·鸿蒙系统·arkui·弹性布局·布局实战·堆叠布局
zhangmeng5 天前
一文带你读懂鸿蒙Stage模型开发运行期和编译期概念
harmonyos·arkts·arkui
simple_lau5 天前
浅谈鸿蒙多线程
harmonyos·arkts·arkui
simple_lau5 天前
鸿蒙开发如何与穿戴设备通讯
harmonyos·arkts·arkui
Huang兄8 天前
鸿蒙-http 和 rcp 抓包,应该如何配置?
harmonyos·arkts·arkui
simple_lau9 天前
如何发布HarmonyOS应用
harmonyos·arkts·arkui
娅娅梨13 天前
HarmonyOS-ArkUI V2装饰器-@Once
华为·harmonyos·arkts·arkui·移动端开发