# 鸿蒙 HarmonyOS 应用开发实战(第25期)|骰子(Dice Roller)— Unicode 符号与动画渲染精讲

发布时间:2026/7/29 0:15:38
# 鸿蒙 HarmonyOS 应用开发实战(第25期)|骰子(Dice Roller)— Unicode 符号与动画渲染精讲 一、应用概述骰子Dice Roller是一款经典的休闲娱乐应用模拟了真实掷骰子的过程。应用投掷两个骰子六面标准骰使用 Unicode 骰面符号直观展示每个骰子的点数并伴有快速滚动的动画效果。每次掷骰后应用会自动计算点数总和并根据特殊的点数组合如蛇眼、Lucky 7、双六给出趣味描述。应用基于 HarmonyOS 的 ArkTS 语言和声明式 UI 框架构建完美展示了 Unicode 特殊符号渲染、animation 动画属性、setInterval 定时器、以及 get 计算属性等核心技术的综合运用。对于鸿蒙开发者而言骰子应用是一个展示符号渲染与动画技巧的绝佳案例——它让你在约85行代码中同时掌握Unicode 符号映射、定时器驱动动画、条件描述逻辑、统计追踪四大核心能力这些能力广泛适用于游戏、抽奖、模拟器等场景。1.1 功能特性双骰子投掷模拟两个六面骰子的随机投掷Unicode 骰面显示使用 ⚀⚁⚂⚃⚄⚅ 符号直观展示点数滚动动画60ms 间隔快速变化模拟真实骰子滚动点数总和计算自动计算两个骰子点数和趣味描述特殊组合2点/3点/7点/12点触发趣味文案投掷统计记录总共投掷次数动画锁定动画进行中防止重复点击1.2 适用场景桌游电子化辅助工具聚会活动抽奖环节概率统计教学演示儿童数学启蒙教育二、技术架构2.1 整体架构概览┌─────────────────────────────────────────┐ │ 数据层 │ │ dice1 / dice2 (1~6 整数) │ │ total (点数总和) │ │ isRolling (动画状态) │ │ rollCount (投掷统计) │ ├─────────────────────────────────────────┤ │ 状态管理层 │ │ State 驱动 UI 重新渲染 │ ├─────────────────────────────────────────┤ │ 业务逻辑层 │ │ roll() —— 掷骰子 动画 │ │ diceFace() —— 数字转 Unicode 符号 │ │ get d1/d2 —— 动画期间的实时随机值 │ │ get description —— 特殊组合描述 │ ├─────────────────────────────────────────┤ │ UI 表示层 │ │ 两个骰子显示 / 点数总和 / 趣味描述 / │ │ 投掷统计 / 掷骰按钮 │ └─────────────────────────────────────────┘2.2 动画状态机静止状态 (isRollingfalse) │ │ 点击掷骰子 ▼ 动画状态 (isRollingtrue) │ │ setInterval(60ms) × 12次 │ 每次更新 dice1/dice2 为随机值 │ UI 显示实时随机值 ▼ 判定状态 (count 12) │ │ clearInterval │ isRolling false │ 计算 total / description │ rollCount ▼ 静止状态 (等待下次投掷)三、核心代码深度分析3.1 完整的页面源码import { router } from kit.ArkUI; Entry Component struct index25 { State dice1: number 1; State dice2: number 6; State total: number 7; State isRolling: boolean false; State rollCount: number 0; // 动画期间的实时随机值 get d1(): number { return this.isRolling ? Math.floor(Math.random() * 6) 1 : this.dice1; } get d2(): number { return this.isRolling ? Math.floor(Math.random() * 6) 1 : this.dice2; } roll() { if (this.isRolling) return; this.isRolling true; let count 0; const intervalId setInterval(() { this.dice1 Math.floor(Math.random() * 6) 1; this.dice2 Math.floor(Math.random() * 6) 1; count; if (count 12) { clearInterval(intervalId); this.isRolling false; this.total this.dice1 this.dice2; this.rollCount; } }, 60); } // 数字转 Unicode 骰面符号 diceFace(val: number): string { const faces [⚀, ⚁, ⚂, ⚃, ⚄, ⚅]; return faces[val - 1]; } // 趣味描述 get description(): string { const t this.total; if (t 2) return 蛇眼; if (t 7) return Lucky 7!; if (t 12) return 双六; if (t 3) return 霉运; return ; } build() { Column() { Row() { Text(‹ 返回).fontSize(16).fontColor(#0077FF).onClick(() router.back()) Text( 骰子).fontSize(18).fontWeight(FontWeight.Bold) Blank() }.width(92%).padding({ top: 16, bottom: 8 }) Column() { // 双骰子展示 Row({ space: 20 }) { Column() { Text(this.diceFace(this.isRolling ? this.d1 : this.dice1)) .fontSize(80).animation({ duration: 60 }) Text(骰子 1).fontSize(14).fontColor(#888) } Column() { Text(this.diceFace(this.isRolling ? this.d2 : this.dice2)) .fontSize(80).animation({ duration: 60 }) Text(骰子 2).fontSize(14).fontColor(#888) } }.margin({ bottom: 16 }) // 点数显示 Text(点数: ${this.isRolling ? ... : this.total}) .fontSize(36).fontWeight(FontWeight.Bold).fontColor(#F44336) // 趣味描述 Text(this.description).fontSize(18).fontColor(#FF9800).margin({ top: 4 }) // 投掷统计 Text(已掷 ${this.rollCount} 次).fontSize(14).fontColor(#888).margin({ top: 8 }) // 掷骰按钮 Button( 掷骰子).width(200).height(56).borderRadius(28) .backgroundColor(#4CAF50).fontSize(22).fontWeight(FontWeight.Bold) .margin({ top: 16 }).onClick(() this.roll()) } .layoutWeight(1).justifyContent(FlexAlign.Center) } .width(100%).height(100%).backgroundColor(#f8f8f8) } }3.2 Unicode 骰面符号映射diceFace(val: number): string { const faces [⚀, ⚁, ⚂, ⚃, ⚄, ⚅]; return faces[val - 1]; }这是本应用最独特的设计——使用 Unicode 的弥生骰子符号Miscellaneous Symbols来展示骰面数字Unicode字符描述1U2680⚀白色骰子12U2681⚁白色骰子23U2682⚂白色骰子34U2683⚃白色骰子45U2684⚄白色骰子56U2685⚅白色骰子6这些 Unicode 字符在支持它们的字体中会渲染为带点阵的骰面图案无需使用图片资源即可获得良好的视觉效果。这种纯文本符号的方案比图片方案具有以下优势无资源依赖不需要额外加载图片减小应用体积矢量缩放任意放大倍数下保持清晰无锯齿主题适配颜色可以通过 CSS 属性自由控制3.3 动画期间实时随机值get d1(): number { return this.isRolling ? Math.floor(Math.random() * 6) 1 : this.dice1; } get d2(): number { return this.isRolling ? Math.floor(Math.random() * 6) 1 : this.dice2; }这是一个精妙的设计——在动画期间每次 UI 渲染时都实时生成新的随机值而非等待setInterval更新State变量。这样做的好处更高的刷新率脱离 60ms 定时器的限制随 UI 渲染帧率同步更新更流畅的动画渲染引擎每帧都看到新值视觉上更加流畅资源节约无需额外的定时器管理动画结束后的判定逻辑if (count 12) { clearInterval(intervalId); this.isRolling false; // 停止实时随机 this.total this.dice1 this.dice2; this.rollCount; }当isRolling设为false后get d1()返回固定的this.dice1值即setInterval最后一次设置的值骰子显示定格。3.4 animation 动画属性Text(this.diceFace(...)) .fontSize(80).animation({ duration: 60 })animation()是 HarmonyOS 中用于为组件添加过渡动画的属性方法。它的参数是一个AnimationOptions对象包含以下常用属性duration动画持续时间毫秒默认1000curve动画曲线Curve.EaseInOut等默认Curve.Easedelay动画延迟开始的时间毫秒iterations动画重复次数-1表示无限循环playMode播放模式PlayMode.Normal/PlayMode.Reverse/ …在本应用中animation({ duration: 60 })设置为60ms的过渡动画。当骰子符号从 ⚀ 变为 ⚅ 时这个过渡动画让变化过程更加平滑而非生硬的瞬间切换。需要注意的是这里的animation属性作用于组件属性变化时的过渡效果。当diceFace()的返回值变化时文字内容变化动画会尝试在变化前后之间进行过渡。但对于文字内容变化过渡效果可能不如数值属性如width、opacity、rotate等明显。3.5 趣味描述逻辑get description(): string { const t this.total; if (t 2) return 蛇眼; // 两个1点 if (t 7) return Lucky 7!; // 最常见的点数 if (t 12) return 双六; // 两个6点 if (t 3) return 霉运; // 12 最小非蛇眼组合 return ; // 其他组合不显示描述 }四种特殊组合的判定规则蛇眼Snake Eyes两个骰子都是1点总和2 —— 骰子中最小的组合名字源于两个1点看起来像蛇的眼睛Lucky 7总和7 —— 两个骰子点数和为7的概率最高1/6被视为幸运数字双六Boxcars两个骰子都是6点总和12 —— 最大的组合霉运总和312—— 仅次于蛇眼的坏运气组合其他的组合4、5、6、8、9、10、11不显示趣味描述保持界面简洁。四、HarmonyOS 特性深度解析4.1 get 计算属性的实时求值机制本应用中使用了三个get计算属性d1、d2、description它们在每次 UI 渲染时被重新求值。这种机制的关键理解是// 在模板中引用 get 属性 Text(this.diceFace(this.isRolling ? this.d1 : this.dice1))ArkTS 的渲染引擎在每次渲染周期中检测到State变量变化如isRolling从false变为true触发重新渲染重新求值所有模板表达式计算this.d1→ 调用get d1()→ 如果是动画状态则生成随机值计算this.diceFace(随机值)→ 映射为 Unicode 符号更新 UI 显示这个链条中get d1()在动画期间每次渲染都生成不同的随机值产生了持续的视觉变化。4.2 setInterval 的正确清理时机roll() { if (this.isRolling) return; this.isRolling true; let count 0; const intervalId setInterval(() { // ... if (count 12) { clearInterval(intervalId); // 在回调内部清理 this.isRolling false; } }, 60); }定时器的清理发生在回调函数内部通过count计数达到阈值时。这种自清理模式的好处确定性清理清理时机明确且可控无需外部干预不需要在aboutToDisappear中额外清理避免内存泄漏定时器在完成任务后立即释放相比而言如果定时器是持续运行的如时钟应用则必须在aboutToDisappear中清理。4.3 条件渲染的不同模式本应用在三个地方使用了条件渲染展示了三种不同的场景// 模式1三元表达式 - 用于文字内容 Text(点数: ${this.isRolling ? ... : this.total}) // 模式2三元表达式 - 用于 get 属性选择 Text(this.diceFace(this.isRolling ? this.d1 : this.dice1)) // 模式3get 属性条件返回 - 用于描述文字 get description(): string { if (...) return ...; return ; }这三种模式分别适用于内联条件简单的文字内容切换值选择器根据状态选择不同的数据源计算属性复杂的多分支逻辑4.4 绿色主题的按钮设计Button( 掷骰子).width(200).height(56).borderRadius(28) .backgroundColor(#4CAF50).fontSize(22).fontWeight(FontWeight.Bold)按钮使用了 Material Design 的绿色#4CAF50在心理学上绿色代表开始和行动。大尺寸200×56、大圆角28px和大字体22px的设计让按钮成为页面中最重要的视觉焦点吸引用户点击。五、UI/UX 设计模式5.1 页面布局结构┌─────────────────────────────────┐ │ Row: 导航栏 │ ├─────────────────────────────────┤ │ Column: 内容区 (居中) │ │ ├── Row: 两个骰子 │ │ │ ├── 骰子1 (⚀~⚅) │ │ │ └── 骰子2 (⚀~⚅) │ │ ├── Text: 点数总和 (大号红色) │ │ ├── Text: 趣味描述 (橙色) │ │ ├── Text: 投掷次数 (灰色) │ │ └── Button: 掷骰子 │ └─────────────────────────────────┘5.2 视觉层次与色彩搭配元素颜色作用骰子符号默认黑色核心视觉元素80px超大字号点数总和#F44336红色最重要的结果信息趣味描述#FF9800橙色次要的趣味性信息掷骰按钮#4CAF50绿色行动召唤CTA统计次数#888灰色辅助信息5.3 信息层级设计信息按照重要性从上到下排列骰子符号最大最醒目—— 核心视觉点数总和36px红色—— 核心数据趣味描述18px橙色—— 情感化反馈投掷次数14px灰色—— 辅助统计每个层级之间通过margin、字号和颜色差异形成清晰的区分。六、最佳实践与经验总结6.1 随机数的正确生成Math.floor(Math.random() * 6) 1这是生成 1~6 范围内随机整数的标准写法。分解如下Math.random()生成 [0, 1) 区间的浮点数含0不含1* 6扩展到 [0, 6) 区间Math.floor()向下取整到 [0, 5] 整数 1偏移到 [1, 6]重要提示在鸿蒙开发中Math.random()是伪随机数生成器对于游戏类应用足够了。6.2 动画期间的防重入roll() { if (this.isRolling) return; this.isRolling true; // ... }isRolling标志位实现了按钮防重入。在动画进行中即使用户多次点击掷骰子按钮roll()方法也会在入口处直接返回不会启动新的动画循环。这是交互设计中防止意外操作的关键机制。6.3 Unicode 符号的兼容性Unicode 骰面符号U2680~U2685属于 Unicode 3.0 标准在现代设备和操作系统中都有良好的支持。但在某些老旧设备或不支持这些符号的字体中可能会显示为空白或方框。在生产环境中建议提供降级方案检测符号渲染情况如果无法正常显示则使用数字替代使用自定义字体打包包含这些符号的字体文件图片备选在极端情况下回退到图片显示6.4 代码组织建议对于更复杂的骰子应用可以考虑以下优化方向多种骰子类型支持4面D4、8面D8、10面D10、12面D12、20面D20等角色扮演游戏常用骰子投掷历史记录保存最近几次投掷的结果统计图表展示点数分布的概率统计shake 传感器利用设备加速度传感器通过摇动手机触发掷骰联机对战通过分布式能力实现多人掷骰比大小七、总结骰子应用在约85行代码中精彩展示了 ArkTS 声明式 UI 开发的多个核心概念Unicode 符号映射使用 ⚀⚁⚂⚃⚄⚅ 纯文本方式渲染骰面get 实时随机值动画期间每次渲染生成新随机数setInterval 定时器动画60ms 间隔的快速滚动效果animation 过渡动画属性变化的平滑过渡防重入机制isRolling 标志位的按钮锁定条件描述逻辑特殊点数组合的趣味反馈这个应用以掷骰子这一简单的游戏需求为切入点展示了纯文本符号渲染和定时器动画的核心技术。它不仅是桌游爱好者的实用工具更是学习 ArkTS 动画编程和符号处理的优秀教学案例。简洁的代码背后蕴含着丰富的交互设计智慧和性能优化技巧。