鸿蒙新特性:Radio 单项选择组件——构建健康评估问卷

单选是表单中最基础的交互。性别选择、支付方式、评分档位、问卷答案——所有这些"多选一"的场景都需要单选按钮。Radio 组件通过互斥的圆形按钮和清晰的选中标记,让用户在多个互斥选项中做出明确的单一选择。

HarmonyOS NEXT ArkUI 提供了 Radio 组件——一个标准的单项选择控件,通常与group属性配合使用实现组内互斥。本文将深入讲解 Radio 组件与 Radio 组的 API,并构建一个"健康评估问卷"——支持 5 道单选题、自动评分、健康等级分级和重新评估。

关键词:HarmonyOS、ArkUI、Radio、单项选择、问卷调查、健康评估、自动评分

一、Radio 组件 API

1.1 基本用法

Radio({value:'0',group:'question1'}).checked(this.selectedOption===0).width(24).height(24).radioStyle({checkedBackgroundColor:'#1677FF'})

核心参数与属性:

参数/属性类型说明
valuestring该选项的值标识
groupstring组名,同组 Radio 互斥
.checked()boolean是否选中(@State驱动)
.radioStyle()RadioStyle自定义选中状态的样式
.width()/.height()Length按钮尺寸

1.2 group 互斥机制

Radio 的互斥通过group属性实现——所有group值相同的 Radio 自动互斥,用户选择其中一个时,同组其他 Radio 自动取消选中:

// 问题 1 的 4 个选项——所有 group 都是 'question1'Radio({value:'0',group:'question1'})// 选项 ARadio({value:'1',group:'question1'})// 选项 BRadio({value:'2',group:'question1'})// 选项 CRadio({value:'3',group:'question1'})// 选项 D// 问题 2 的 4 个选项——所有 group 都是 'question2'Radio({value:'0',group:'question2'})// 选项 ARadio({value:'1',group:'question2'})// 选项 B// ...

问题 1 和问题 2 的 Radio 使用不同的group值,因此互不影响。用户可以在问题 1 选 A、在问题 2 选 C——两者互不干扰。

Demo 中通过'q'.concat(qIdx.toString())动态生成组名,例如问题 0 的组名为'q0',问题 1 的组名为'q1',以此类推。

1.3 checked 与 @State 联动

Radio 的checked属性需要手动绑定@State变量来控制选中状态:

Radio({value:'0',group:'question1'}).checked(this.answers[0]===0)

这里this.answers[0]存储问题 1 的选中选项索引(-1表示未选,0/1/2/3表示已选)。当answers[0] === 0时,第一个 Radio 显示选中状态;当用户点击其他 Radio 时,answers[0]更新为新索引,之前的 Radio 自动取消选中。

这种"用@State数组管理所有问题答案"的模式让 5 道题的答案统一存储、统一管理、统一重置。

1.4 radioStyle 自定义样式

.radioStyle({checkedBackgroundColor:'#1677FF'})

checkedBackgroundColor控制选中时内圆点的填充颜色。默认的灰色选中圆点可能不够醒目,自定义为蓝色后与页面主题色一致,选中状态更清晰。

1.5 行级点击区域

Radio 按钮本身只有 24×24 的点击区域,在移动端不够大。Demo 中将整个选项行设置为可点击:

Row(){Radio({value:...}).width(24).height(24)Text(option.label)}.onClick(()=>{this.selectAnswer(qIdx,oIdx);})

用户点击"选项行"的任意位置(包括 Radio 和文字)都会触发选择,而不仅仅是点击 Radio 小圆圈。这显著提升了移动端的操作体验。

1.6 选中行的视觉反馈

选中行使用浅蓝背景(#F0F5FF),未选中行使用浅灰背景(#F8F9FA),选中文字更深更粗:

.fontColor(this.answers[qIdx]===oIdx?'#1a1a2e':'#888899').fontWeight(this.answers[qIdx]===oIdx?FontWeight.Medium:FontWeight.Normal).backgroundColor(this.answers[qIdx]===oIdx?'#F0F5FF':'#F8F9FA')

这种整行高亮的设计让用户一眼就能看到每道题的当前选择,无需寻找那个小小的 Radio 按钮。

二、健康评估问卷的整体设计

2.1 页面架构

SurveyPage ├── 标题栏 — "健康评估" + 进度计数(已答/总题数) ├── 答题模式(submitted = false) │ ├── 问题 1: 😴 睡眠时长 — 4 个 Radio 选项 │ ├── 问题 2: 🏃 运动频率 — 4 个 Radio 选项 │ ├── 问题 3: 💧 饮水量 — 4 个 Radio 选项 │ ├── 问题 4: 🧠 压力感受 — 4 个 Radio 选项 │ ├── 问题 5: 🍽️ 饮食习惯 — 4 个 Radio 选项 │ └── 提交按钮(全部完成时激活) └── 结果模式(submitted = true) ├── 健康等级 emoji + 标签 + 总分 ├── 健康建议文字 └── "重新评估"按钮

2.2 数据结构

classQuestionOption{label:string;// 选项文字score:number;// 该选项的分值(1-4)}classQuestion{id:number;title:string;// 问题文字icon:string;// 图标 emojioptions:QuestionOption[];// 4 个选项}

5 个问题覆盖了健康评估的核心维度:

问题图标4 个选项的分值
睡眠时长😴不足5h(1) / 5-7h(2) / 7-8h(3) / >8h(4)
运动频率🏃几乎不(1) / 1-2次(2) / 3-4次(3) / >5次(4)
饮水量💧不足3杯(1) / 3-5杯(2) / 6-8杯(3) / >8杯(4)
压力感受🧠很大(1) / 较大(2) / 一般(3) / 轻松(4)
饮食习惯🍽️偏油腻(1) / 偏清淡(2) / 均衡(3) / 规划(4)

每题 4 个选项,分值从 1 到 4,总分范围 5-20。分值越高代表生活习惯越好。

2.3 答案存储

@Stateanswers:number[]=[-1,-1,-1,-1,-1];

5 个元素的数组,-1表示未选,0/1/2/3表示选中的选项索引。用户每点击一个选项,selectAnswer通过slice()创建新数组并更新对应索引:

selectAnswer(questionIdx:number,optionIdx:number):void{letnewAnswers=this.answers.slice();newAnswers[questionIdx]=optionIdx;this.answers=newAnswers;}

注意这里使用了let newAnswers = this.answers.slice()(在方法内部而非 UI 函数中),这符合 ArkTS 的语法规则。

三、评分与结果

3.1 总分计算

getTotalScore():number{letscore=0;for(leti=0;i<this.answers.length;i++){letidx=this.answers[i];if(idx>=0){score+=this.getQuestions()[i].options[idx].score;}}returnscore;}

遍历所有已答问题,累加各选项的分值。getQuestions()[i].options[idx].score通过问题索引和选项索引两级查找获取分值——这种设计让分值始终与选项绑定,修改选项时只需改一处。

3.2 健康等级评定

getHealthLevel():HealthLevel{letscore=this.getTotalScore();if(score>=18)returnnewHealthLevel('非常健康','#52C41A','...','🎉');if(score>=14)returnnewHealthLevel('比较健康','#1677FF','...','👍');if(score>=10)returnnewHealthLevel('需要关注','#FAAD14','...','⚠️');returnnewHealthLevel('急需调整','#FF4D4F','...','❗');}

HealthLevel是一个专门的类(而非匿名对象——ArkTS 要求所有对象字面量对应显式声明的类型),包含 4 个字段:

字段说明
label等级名称
color主题色(绿/蓝/金/红)
desc个性化疗建议
emoji等级图标

四个等级的颜色映射:

  • 绿色(18-20 分):非常健康——积极完成
  • 蓝色(14-17 分):比较健康——肯定鼓励
  • 金色(10-13 分):需要关注——温和警示
  • 红色(5-9 分):急需调整——强烈提醒

3.3 结果卡片

提交后,页面从"答题模式"切换为"结果模式"——问题列表隐藏,取而代之的是一个结果卡片:

  • 大号 emoji(48px)
  • 健康等级名称(24px,等级主题色)
  • 总分显示(“总分: 16 / 20”)
  • 健康建议文字(13px,灰色)
  • "重新评估"按钮(等级主题色圆角)

3.4 重新评估

retakeSurvey():void{this.answers=[-1,-1,-1,-1,-1];this.submitted=false;}

将答案重置为全-1(未选状态),submitted切回false。页面回到答题模式,所有 Radio 恢复未选中状态,提交按钮恢复禁用状态。

四、提交控制

4.1 完成度检测

isComplete():boolean{for(leti=0;i<this.answers.length;i++){if(this.answers[i]===-1)returnfalse;}returntrue;}

当所有 5 题都已选择选项(answers中无-1)时,isComplete()返回true。提交按钮根据此状态变换样式和行为:

Text(this.isComplete()?'提交评估':'请完成所有题目后提交').fontColor(this.isComplete()?'#FFFFFF':'#BBBBCC')// 背景色变化.backgroundColor(this.isComplete()?'#1677FF':'#F8F9FA')// 点击事件守卫.onClick(()=>{if(this.isComplete()){this.submitSurvey();}})

未完成时:灰色文字 + 浅灰背景 + 点击无效。完成后:白色文字 + 蓝色背景 + 可点击提交。

4.2 进度计数

标题栏右侧显示"已答 / 总题数"计数:

Text(this.getAnswerCount().toString().concat('/').concat(this.getQuestions().length.toString()))
getAnswerCount():number{letcount=0;for(leti=0;i<this.answers.length;i++){if(this.answers[i]!==-1)count++;}returncount;}

随着用户逐题作答,计数从 “0/5” 递增到 “5/5”,给用户清晰的任务完成感。

五、页面状态切换

Demo 包含两种页面状态,由submitted控制:

  • 答题模式submitted = false):显示 5 个问题卡片 + 提交按钮
  • 结果模式submitted = true):显示结果卡片(问题列表隐藏)

两种状态共用同一个Scroll容器,通过if (this.submitted)if (!this.submitted)条件渲染切换。切换时页面滚动位置自然回到顶部(因为内容完全替换),用户看到结果卡片位于屏幕上方。

六、交互流程演示

6.1 开始答题

进入页面,5 道题的所有选项均为未选中状态。标题栏显示"0/5"。提交按钮显示"请完成所有题目后提交",灰底灰字不可点击。

6.2 逐题作答

点击第 1 题(睡眠时长)的第 3 个选项"7-8 小时"。该选项行变为浅蓝背景,Radio 内圆点变为蓝色,文字变深加粗。标题栏计数变为"1/5"。

依次完成其余 4 题。标题栏从"2/5"递增到"5/5"。完成第 5 题后,提交按钮变为蓝底白字"提交评估",提示用户可以提交。

6.3 查看结果

点击"提交评估"。Toast 提示"评估完成,查看结果"。页面切换为结果模式——结果卡片显示健康等级、总分和个性化建议。"重新评估"按钮位于卡片底部。

6.4 重新评估

点击"重新评估"。页面回到答题模式,所有选项恢复未选中。标题栏计数归零"0/5",提交按钮恢复灰色禁用状态。用户可以修改选择并重新提交。

七、总结

本文通过"健康评估问卷"这个实战案例,全面讲解了 ArkUI Radio 单项选择组件的使用方法。核心知识点包括:

  1. Radio 基础 APIvalue+group组内互斥 +.checked()状态绑定
  2. 选项行交互设计:整行点击 + 选中高亮背景 + 文字颜色/粗细变化
  3. 答案管理@State数组统一存储 +slice()不可变更新
  4. 自动评分:选项分值绑定 + 总分累加 + 四级健康等级判定
  5. 完成度控制isComplete()检测 + 按钮样式/行为条件切换
  6. 双状态切换:答题模式 vs 结果模式 + 重新评估重置
  7. 对象字面量约束:返回值类型必须使用显式声明的 class(HealthLevel

单选是移动表单的基础组件。一个好的单选体验不仅仅是"能点一个圆"——它需要清晰的选中视觉反馈、足够的点击热区、组间独立互不干扰的互斥逻辑和流畅的答案管理。ArkUI 的 Radio 组件提供了简洁的value+groupAPI,让开发者将注意力集中在问题的组织、答案的存储和评分的计算上。