HarmonyOS应用开发实战:猫猫大作战-Button 颜色系统与视觉语义

📅 2026/7/28 2:50:25 👁️ 阅读次数 📝 编程学习
HarmonyOS应用开发实战:猫猫大作战-Button 颜色系统与视觉语义

前言

上一篇我们用Row+Spacer搭好了底部双按钮栏,但只是把按钮「摆上去」——按钮的视觉语义圆角尺寸点击反馈都还没讲透。这一篇专攻底部栏里那个灰色的「暂停」按钮,把Button的颜色系统、圆角档位、stateEffect点击反馈、buttonStyle视觉态四大要点一次讲透。

本篇以「猫猫大作战」底部暂停按钮为锚点。读完本篇你将能独立写出:主操作绿色按钮次要操作灰色按钮危险操作红色按钮三种视觉语义的 Button,并掌握圆角档位与点击反馈的搭配套路。

提示:本系列不讲 ArkTS 基础语法与环境搭建,假设你已跟完第 1–18 篇。本篇是 Button 组件的进阶样式篇。

一、场景拆解:暂停按钮的视觉规格

打开entry/src/main/ets/pages/Index.etsGameView底部栏,暂停按钮代码如下:

// 来源:entry/src/main/ets/pages/Index.ets GameView() 底部栏 Button('暂停') .width(100) .height(44) .fontSize(15) .fontColor('#FFFFFF') .backgroundColor('#95A5A6') .borderRadius(22) .onClick(() => { this.pauseGame(); })

这条按钮的视觉规格拆解:

属性含义
width100按钮宽 100vp
height44按钮高 44vp
fontSize15文字字号 15vp
fontColor#FFFFFF白色文字
backgroundColor#95A5A6灰色背景
borderRadius22圆角 = height/2 = 胶囊形

关键经验Button 的视觉规格 = 尺寸 + 圆角 + 颜色 + 字号四大要素,缺一不可。

二、Button 的颜色系统

2.1 色彩语义三档

ArkUI 没有强制按钮颜色规范,但业界有共识——按钮颜色 = 用户引导

语义颜色hex用途本项目位置
主操作成功绿#2ECC71引导用户首选的操作开始游戏按钮
次要操作中性灰#95A5A6不强推、随时可点暂停按钮
危险操作警告红#E74C3C不可逆、需谨慎重新开始按钮
中性重置提醒橙#F39C12介于次要与危险之间暂停弹窗的「重新开始」

提示:「重新开始」在底部栏是红色,在暂停弹窗里是橙色——底部栏的重新开始会清空进度(危险),暂停弹窗的重新开始同样清空进度,但用户已经在暂停态,意图更明确,所以用更温和的橙色。

2.2 字色对比度

.fontColor('#FFFFFF') // 白字 .backgroundColor('#95A5A6') // 灰底

对比度公式:WCAG 建议正文与背景对比度 ≥ 4.5:1。本项目按钮配色对比度:

背景字色对比度达标
#95A5A6#FFFFFF2.7:1❌ 低于 4.5
#E74C3C#FFFFFF3.3:1
绿#2ECC71#FFFFFF1.9:1

踩坑:按 WCAG 严格标准,这些按钮都不达标。但大字号(≥18pt 或 14pt 粗体)放宽到 3:1,本项目按钮字号 15vp 不算大字。

实战经验游戏类应用色彩对比度可适当放宽——视觉风格优先于无障碍标准。生产环境建议把灰底调深到#7F8C8D(对比度 4.6:1 达标)。

2.3 纯色 vs 渐变

// 写法 1:纯色(本项目) .backgroundColor('#95A5A6') // 写法 2:线性渐变(更立体) .linearGradient({ direction: GradientDirection.Bottom, colors: [['#BDC3C7', 0.0], ['#95A5A6', 1.0]] }) // 写法 3:深浅两段(最立体) .linearGradient({ direction: GradientDirection.Bottom, colors: [['#AAB7B8', 0.0], ['#95A5A6', 0.5], ['#7F8C8D', 1.0]] })
方案视觉性能
纯色平面最优
渐变立体中等
三段渐变最立体略低

实战经验移动端按钮建议纯色——渐变在小屏上立体感不明显,但消耗 GPU 填充率。本项目全部用纯色。

三、borderRadius 圆角档位

3.1 圆角档位表

ArkUI 的borderRadius是一个统一圆角值,不同档位视觉差异大:

圆角值视觉适用本项目位置
0直角表格、卡片底
4小圆角输入框、Tag
8中圆角卡片、面板
12大圆角棋盘背景Stack 棋盘
22(=height/2)胶囊形按钮暂停/重新开始按钮
999 / height超大圆角(=胶囊)头像、圆形按钮

关键公式胶囊形圆角 = height / 2。本项目按钮 height=44,圆角=22,正好胶囊形。

3.2 圆角不一致的踩坑

// ❌ 错误:圆角 20 ≠ height/2=22,左右两端不是半圆 Button('暂停').height(44).borderRadius(20) // ✅ 正确:圆角 = height/2,左右两端是完美半圆 Button('暂停').height(44).borderRadius(22)

视觉差异微小但可察觉——圆角 20 时两端略有「直角感」,22 时端到端是平滑半圆。

3.3 四角不同圆角

// 写法 1:统一圆角(本项目,推荐) .borderRadius(22) // 写法 2:四角分别设置 .borderRadius({ topLeft: 22, topRight: 22, bottomLeft: 22, bottomRight: 22 }) // 写法 3:只圆顶部两角(卡片标题区) .borderRadius({ topLeft: 12, topRight: 12, bottomLeft: 0, bottomRight: 0 })

实战经验统一圆角用数字写法(写法 1),四角不同才用对象写法(写法 2、3)。对象写法更冗长但可读性更好,团队协作时统一规范。

四、stateEffect 点击反馈

4.1 默认 stateEffect

Button('暂停') .backgroundColor('#95A5A6') // 默认 stateEffect=true:按下时背景色变浅 30%

ArkUI 的Button有个stateEffect属性,默认true——按下时按钮会有视觉反馈(背景色微微变浅)。

stateEffect按下视觉适用
true(默认)背景变浅,有按压感普通按钮
false无变化,按下「无感」禁用按钮、加载中按钮

4.2 关闭 stateEffect 的场景

// 加载中按钮:禁用点击反馈 Button('加载中...').stateEffect(false).enabled(false) // 禁用按钮:灰化 + 无反馈 Button('不可用').stateEffect(false).backgroundColor('#ECF0F1').fontColor('#BDC3C7')

实战经验禁用按钮同时设stateEffect(false)+enabled(false)——前者去掉按压反馈,后者阻止点击事件。

4.3 自定义按压反馈

ArkUI 内置的stateEffect反馈较微弱,要更强反馈可监听 touch 事件改透明度:

Button('暂停') .backgroundColor('#95A5A6') .opacity(this.isPressed ? 0.7 : 1.0) // 按下 0.7,松开 1.0 .onTouch((event) => { if (event.type === TouchType.Down) this.isPressed = true if (event.type === TouchType.Up) this.isPressed = false })

关键经验简单按钮用默认 stateEffect,强反馈按钮用 opacity + onTouch 自定义。本系列第 30 篇会专讲 AttributeModifier 复用按钮样式。

五、buttonStyle 视觉态

5.1 ButtonStyle 枚举

ArkUI 的Button有三种buttonStyle(API 11+):

ButtonStyle视觉适用
NORMAL(默认)矩形/胶囊,纯色背景通用操作按钮
CAPSULE强制胶囊形,自动 borderRadius移动端主操作
CIRCLE强制圆形(width=height)浮动按钮 FAB、图标按钮
// 写法 1:NORMAL + 手动 borderRadius=22(本项目等效) Button('暂停', { type: ButtonType.Normal }) .height(44).borderRadius(22) // 写法 2:CAPSULE 自动胶囊(最简) Button('暂停', { type: ButtonType.Capsule }) .height(44) // borderRadius 自动 = height/2 // 写法 3:CIRCLE 圆形按钮(FAB) Button('+', { type: ButtonType.Circle }) .width(56).height(56) .backgroundColor('#2ECC71')

关键经验胶囊按钮用ButtonType.Capsule最简——不用手算 borderRadius。本项目用ButtonType.Normal+ borderRadius=22 也能达到胶囊形,但 Capsule 更规范。

5.2 ButtonType 完整对照

// ButtonType.Normal:矩形,需手动设 borderRadius Button('A', { type: ButtonType.Normal }).borderRadius(8) // ButtonType.Capsule:胶囊形,自动圆角 Button('B', { type: ButtonType.Capsule }) // ButtonType.Circle:圆形,width=height 时自动圆 Button('C', { type: ButtonType.Circle }).width(48).height(48)
ButtonType自动圆角需设 width/height视觉
Normal矩形/圆角矩形
Capsule是(=height/2)胶囊
Circle是(=width/2)是(且 width=height)

六、按钮组合:底部栏双按钮配色

回顾底部栏完整按钮配置:

// 来源:entry/src/main/ets/pages/Index.ets GameView() 底部栏 Row() { // 暂停:灰色次要操作 Button('暂停') .width(100).height(44) .fontSize(15).fontColor('#FFFFFF') .backgroundColor('#95A5A6') .borderRadius(22) .onClick(() => { this.pauseGame(); }) Spacer() // 重新开始:红色危险操作 Button('重新开始') .width(100).height(44) .fontSize(15).fontColor('#FFFFFF') .backgroundColor('#E74C3C') .borderRadius(22) .onClick(() => { this.clearTimers(); this.startGame(); }) } .width('100%') .padding({ left: 24, right: 24, bottom: 24, top: 12 })

两按钮差异表

维度暂停重新开始
背景#95A5A6#E74C3C
含义次要操作危险操作
点击pauseGameclearTimers + startGame
失误成本低(可继续)高(进度清零)

七、完整代码:暂停按钮 + pauseGame

// 来源:entry/src/main/ets/pages/Index.ets pauseGame() { if (this.gameState === GameState.PLAYING) { this.gameState = GameState.PAUSED; } } // 底部栏暂停按钮(本篇重点) @Builder GameView() { Column() { this.GameHUD() Column() { /* 预告 + 棋盘 */ }.alignItems(HorizontalAlign.Center) Spacer() Row() { Button('暂停') .width(100).height(44) .fontSize(15).fontColor('#FFFFFF') .backgroundColor('#95A5A6') .borderRadius(22) .onClick(() => { this.pauseGame(); }) Spacer() Button('重新开始') .width(100).height(44) .fontSize(15).fontColor('#FFFFFF') .backgroundColor('#E74C3C') .borderRadius(22) .onClick(() => { this.clearTimers(); this.startGame(); }) } .width('100%') .padding({ left: 24, right: 24, bottom: 24, top: 12 }) } .width('100%').height('100%') .linearGradient({ direction: GradientDirection.Bottom, colors: [['#E8F4F8', 0.0], ['#D6EEF5', 0.5], ['#C9E8F2', 1.0]] }) .alignItems(HorizontalAlign.Center) }

八、踩坑提示

8.1 Button 不设 width/height 会塌缩

// ❌ 错误:只设文字,不设尺寸 Button('暂停').fontSize(15) // Button 默认 wrap_content,宽 = 文字宽 + padding,高 = 文字高 + padding,很小 // ✅ 正确:显式设尺寸 Button('暂停').width(100).height(44)

8.2 backgroundColor 不生效

// ❌ 错误:Button 用了 Capsule 类型但没设 backgroundColor,显示默认蓝 Button('暂停', { type: ButtonType.Capsule }) // 默认蓝主题色 // ✅ 正确:显式设 backgroundColor Button('暂停', { type: ButtonType.Capsule }) .backgroundColor('#95A5A6')

8.3 borderRadius 与 ButtonType 冲突

// ❌ 错误:Capsule 自动圆角,再手动设 borderRadius 会冲突 Button('A', { type: ButtonType.Capsule }).borderRadius(10) // 实际渲染以 Capsule 自动圆角为准,borderRadius 被忽略 // ✅ 正确:Capsule 不设 borderRadius;要自定义圆角用 Normal Button('A', { type: ButtonType.Normal }).borderRadius(10)

8.4 onClick 丢失 this

// ❌ 错误:普通函数 this 不指向组件 Button('暂停').onClick(function () { this.pauseGame() }) // ✅ 正确:箭头函数保留外层 this Button('暂停').onClick(() => { this.pauseGame() })

本系列第 38 篇会专讲箭头函数 this 绑定。

九、调试技巧

  1. 按钮颜色看不到:检查 backgroundColor 是否被父容器的 backgroundColor 覆盖;检查 opacity 是否为 0。
  2. 按钮形状不对:Capsule 类型下别手动设 borderRadius,要自定义圆角改用 Normal。
  3. 点击无反馈:默认 stateEffect=true 会有按压反馈;若关闭了,可通过 onTouch 改 opacity 自定义反馈。
  4. 按钮太小点不到:HarmonyOS 建议最小可点击区域 48×48vp;本项目 100×44vp 宽度够,高度略低,可调到 48vp。

十、性能与最佳实践

  1. 胶囊按钮用 ButtonType.Capsule——自动圆角,不用手算 borderRadius。
  2. 颜色遵循语义——绿主操作、灰次要、红危险、橙中性。
  3. 对比度 ≥ 4.5:1——深底白字或浅底深字,避免中灰底白字。
  4. 禁用按钮双设——stateEffect(false) + enabled(false) 同时设。
  5. 强反馈用 opacity + onTouch——默认 stateEffect 反馈微弱。
  6. 最小点击区 48vp——低于 48vp 容易误触。

总结

本篇我们从暂停按钮样式切入,掌握了Button 颜色语义四档(绿/灰/红/橙)borderRadius 胶囊形公式 = height/2stateEffect 点击反馈与禁用、**buttonStyle 视觉态(Normal/Capsule/Circle)**四大要点,并给出了暂停按钮 + pauseGame 完整代码。核心要点:胶囊按钮用 Capsule 最简;颜色遵循语义;禁用按钮双设 stateEffect+enabled;最小点击区 48vp

下一篇我们将拆解 SymbolGlyph——用系统符号字体替代 Emoji 的方案。

如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!


相关资源:

  • 「猫猫大作战」项目源码:本仓库entry/src/main/ets/pages/Index.ets
  • Button 组件官方指南
  • ButtonType 枚举官方文档
  • borderRadius 圆角属性官方指南
  • ArkUI 无障碍设计最佳实践
  • 开源鸿蒙跨平台社区
  • HarmonyOS 开发者官方文档首页
  • 系列索引:本仓库articles/INDEX.md