拓冰建站拓冰建站
首页 / 资讯中心 / 正文

HarmonyOS 应用 · 寝室投票投票页深度解析:Radio 单选与 enabled 按钮联动

HarmonyOS 应用 · 寝室投票投票页深度解析Radio 单选与 enabled 按钮联动项目编号49-dorm-vote 技术栈HarmonyOS ArkTS · ArkUI 声明式 UI · Stage 模型 本篇页面投票页Func2Tab.ets81 行 系列导航一首页 · 二创建 ·三投票· 四结果一、Option interface 与 selected 状态interface Option { id: number; emoji: string; name: string; }三个字段id是 key 锚点emoji是选项图标name是选项名。StorageProp(safeTop) safeTop: number 0; StorageProp(safeBottom) safeBottom: number 0; State selected: number -1; private options: Option[] [ { id: 1, emoji: , name: 黄焖鸡米饭 }, { id: 2, emoji: , name: 汉堡炸鸡 }, { id: 3, emoji: , name: 披萨意面 }, { id: 4, emoji: , name: 麻辣香锅 } ];State selected: number -1——初始 -1 表示未选中任何选项。-1 是哨兵值selected 0即有选中项驱动按钮的启用/禁用。四个外卖选项黄焖鸡/汉堡炸鸡/披萨意面/麻辣香锅。二、页面骨架QuestionCard OptionList Buttonbuild() { Column() { this.Header() Scroll() { Column({ space: 16 }) { this.QuestionCard() this.OptionList() Button(this.selected 0 ? 确认投票 : 请选择一个选项).fontSize(15) .fontColor(#FFFFFF).backgroundColor(this.selected 0 ? C.primary : C.textDim) .width(100%).height(48).borderRadius(D.rMd) .enabled(this.selected 0) .onClick(() { promptAction.showToast({ message: 投票成功 }); }) } .width(100%) .padding({ left: D.pad, right: D.pad, top: 16, bottom: D.pad this.safeBottom 20 }) } .layoutWeight(1).scrollBar(BarState.Off).align(Alignment.Top) } .width(100%).height(100%).backgroundColor(C.bg) }selected驱动按钮三态——文案、底色、可点性三路分支// 文案确认投票 vs 请选择一个选项 Button(this.selected 0 ? 确认投票 : 请选择一个选项) // 底色粉色 vs 灰色 .backgroundColor(this.selected 0 ? C.primary : C.textDim) // 可点性启用 vs 禁用 .enabled(this.selected 0)enabled()是本页特色——系列首次使用组件禁用属性。未选中时按钮灰色 禁用点击无效选中后按钮变粉 启用——必须选择才能投票的强约束比 Toast 校验更前置。三、Header 与 QuestionCard问题上下文Builder Header() { Row() { Text(参与投票).fontSize(20).fontWeight(FontWeight.Bold).fontColor(C.text) } .width(100%).height(this.safeTop 56).padding({ top: this.safeTop, left: D.pad, right: D.pad }) .backgroundColor(C.card).alignItems(VerticalAlign.Bottom) } Builder QuestionCard() { Column({ space: 8 }) { Text( 今晚点什么外卖).fontSize(18).fontWeight(FontWeight.Bold).fontColor(C.text).width(100%) Text(单选 · 3/4 人已投票 · 剩余 2 小时).fontSize(12).fontColor(C.textDim).width(100%) } .width(100%).padding(16).backgroundColor(C.card).borderRadius(D.rLg).border({ width: 1, color: C.stroke }) }18 号加粗问题 12 号灰色上下文单选 · 3/4 人已投票 · 剩余 2 小时——一句话交代投票类型、进度、剩余时间。问题卡让用户先理解投什么再选择。四、OptionListRadio 单选 卡片边框联动Builder OptionList() { Column({ space: 12 }) { ForEach(this.options, (o: Option, idx: number) { Row({ space: 12 }) { Text(o.emoji).fontSize(26) Text(o.name).fontSize(15).fontColor(C.text).layoutWeight(1) Radio({ value: o.name, group: vote }) .checked(this.selected idx).radioStyle({ checkedBackgroundColor: C.primary }) .onClick(() { this.selected idx; }) } .width(100%).padding(16) .backgroundColor(this.selected idx ? C.primarySoft : C.card).borderRadius(D.rMd) .border({ width: this.selected idx ? 2 : 1, color: this.selected idx ? C.primary : C.stroke }) .onClick(() { this.selected idx; }) }, (o: Option) o.id.toString()) }.width(100%) }Radio组件——系列首次出现的单选组件Radio({ value: o.name, group: vote }) .checked(this.selected idx) .radioStyle({ checkedBackgroundColor: C.primary }) .onClick(() { this.selected idx; })group: vote同组 Radio 互斥单选语义的系统级保证checked(this.selected idx)绑定选中态radioStyle({ checkedBackgroundColor: C.primary })选中圆点粉色。卡片双态联动——selected idx驱动底色与边框// 底色浅粉 vs 白底 .backgroundColor(this.selected idx ? C.primarySoft : C.card) // 边框2px 粉色 vs 1px 浅灰 .border({ width: this.selected idx ? 2 : 1, color: this.selected idx ? C.primary : C.stroke })选中项卡片浅粉底 2px 粉色边框加粗突出未选白底 1px 浅灰边框。整卡onClick设this.selected idx——点击卡片任意位置图标/名称/Radio都能选中。五、单选状态链路selected形成三处联动点击卡片/Radio → selected idx → Radio checked 转移单选互斥 → 卡片底色/边框高亮转移 → 按钮变确认投票粉色 enabled 启用一次点击触发三处刷新——Radio 组互斥 卡片高亮 按钮启用的完整链路。enabled的存在让未选择状态在按钮层面就被拦截无需 Toast 提示。六、可演进方向方向现状改法收益投票写入Toast 模拟服务器提交 票数1真实投票多选支持仅单选multiChoice 时 Checkbox selected 数组单/多选切换倒计时静态剩余 2 小时动态倒计时 到时禁用投票限时投票后反馈Toast跳转结果页查看实时票数闭环反馈已投状态可重复投记录已投选项 按钮变已投一人一票投票页是投票的核心交互——selected驱动 Radio 互斥、卡片高亮、按钮启用的三处联动。从哨兵值 -1 的状态设计到enabled的禁用约束每一层都有明确的职责边界。系列导航一首页 · 二创建 ·三投票· 四结果
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门