HarmonyOS ArkTS 按钮状态样式库:主按钮 / 次按钮 / 危险按钮(可直接复制用,带 stateStyles + 工程化写法)
这份是我按“真实项目能落地”的思路整理的按钮样式库:主按钮(Primary)/ 次按钮(Secondary)/ 危险按钮(Danger) 。 写法上我推荐用
@Extend(Button)+stateStyles组合:
@Extend让你在页面里直接.primaryBtn()/.secondaryBtn()/.dangerBtn()stateStyles负责按下/获焦/禁用的多态表现(不用你写 onTouch/onFocus)
你复制完,页面里写按钮就会变得非常干净: Button('提交', ...).primaryBtn() 这种。
0. 设计目标(我做按钮样式时最在意的 5 件事)
- 正常态要“明确” :主按钮一眼就知道是主要操作
- 按下态要“有反馈” :不然用户会怀疑没点到
- 获焦态要“能用在 TV/车机/键盘” :焦点可视化必须清晰
- 禁用态要“像禁用” :不只是变灰,还要显得不可点击
- 风格统一:圆角、字号、间距一致,后期改版才不崩
1. 推荐落地方式:一个文件搞定三种按钮
你可以新建一个文件,比如:
entry/src/main/ets/styles/button.extend.ets
然后把下面内容直接放进去。
2. 代码:按钮基础规范(高度、圆角、字号等)
我会先做一个“基础按钮规范”,因为项目里按钮的高度、圆角、字体不统一,后面维护会很痛。
建议规范(你也可以按你项目改)
- 高度:44(移动端常用)
- 圆角:12(比较现代)
- 字体:16,略加粗
- 宽度:默认 100%(表单页最常见)
3. 主按钮 Primary(最常用)
3.1 主按钮应该是什么样?
主按钮一般承担“提交/保存/确认/下一步”,所以:
- 颜色饱和、对比强
- 文本白色
- 按下变深
- 获焦给清晰描边(尤其 TV/车机)
3.2 主按钮 Extend + stateStyles
// entry/src/main/ets/styles/button.extend.ets
@Extend(Button)
export function primaryBtn() {
this
.height(44)
.width('100%')
.borderRadius(12)
.stateStyles({
normal: {
.backgroundColor('#2F7BFF') // 主色蓝
.fontColor('#FFFFFF')
.fontSize(16)
.fontWeight(FontWeight.Medium)
},
pressed: {
.backgroundColor('#1F5FE0') // 按下更深
},
focused: {
.border({ width: 2, color: '#FFCC00' }) // 获焦描边(黄)
},
disabled: {
.backgroundColor('#CFCFCF')
.fontColor('#8A8A8A')
}
})
}
3.3 页面里怎么用(很“顺手”)
Button('提交', () => {
// submit...
}).primaryBtn()
4. 次按钮 Secondary(更克制,但要清晰)
4.1 次按钮通常用在哪?
比如:
- “取消”
- “稍后再说”
- “查看详情”(不是主要动作)
它不应该抢主按钮的注意力,但也不能“像个链接一样弱”。
常见做法:
- 浅底 + 深字
- 或者 描边按钮(ghost)
- 按下态变浅灰/加深描边
4.2 次按钮 Extend + stateStyles(描边方案更耐用)
@Extend(Button)
export function secondaryBtn() {
this
.height(44)
.width('100%')
.borderRadius(12)
.stateStyles({
normal: {
.backgroundColor('#FFFFFF')
.fontColor('#2F7BFF') // 用主色做文字
.fontSize(16)
.fontWeight(FontWeight.Medium)
.border({ width: 1, color: '#2F7BFF' })
},
pressed: {
.backgroundColor('#EEF4FF') // 轻微填充,告诉用户“按下了”
},
focused: {
.border({ width: 2, color: '#FFCC00' }) // 获焦描边
},
disabled: {
.backgroundColor('#FFFFFF')
.fontColor('#B0B0B0')
.border({ width: 1, color: '#D9D9D9' })
}
})
}
4.3 页面用法
Button('取消', () => {
// cancel...
}).secondaryBtn()
5. 危险按钮 Danger(用得少,但必须“像危险”)
5.1 危险按钮的典型场景
- 删除
- 清空
- 解绑
- 退出登录(如果产品定义为危险操作)
危险按钮的设计原则:
- 红色要明确
- 按下更深
- 禁用更灰
- 尽量不要和主按钮同屏并排抢焦点(除非产品强要求)
5.2 危险按钮 Extend + stateStyles
@Extend(Button)
export function dangerBtn() {
this
.height(44)
.width('100%')
.borderRadius(12)
.stateStyles({
normal: {
.backgroundColor('#FF4D4F') // 常见危险红
.fontColor('#FFFFFF')
.fontSize(16)
.fontWeight(FontWeight.Medium)
},
pressed: {
.backgroundColor('#D9363E') // 按下更深
},
focused: {
.border({ width: 2, color: '#FFCC00' }) // 统一焦点色,体验一致
},
disabled: {
.backgroundColor('#E6E6E6')
.fontColor('#9B9B9B')
}
})
}
5.3 页面用法
Button('删除账号', () => {
// delete...
}).dangerBtn()
6. 推荐的“按钮组”排版(真实页面最常见)
6.1 主 + 次(表单页经典)
Column({ space: 12 }) {
Button('保存', () => {}).primaryBtn()
Button('取消', () => {}).secondaryBtn()
}
6.2 危险按钮单独放(别和主按钮挤一起)
Column({ space: 12 }) {
Button('退出登录', () => {}).dangerBtn()
}
7. 我个人会加的两个“细节优化”(很像真实项目)
7.1 Loading 态(主按钮经常需要)
建议你在业务层做一个 @State loading,然后:
- loading 时
enabled(false) - 文案变成“提交中…”
@State submitting: boolean = false
Button(this.submitting ? '提交中…' : '提交', () => {
this.submitting = true
// async submit...
})
.enabled(!this.submitting)
.primaryBtn()
7.2 小按钮/紧凑按钮(列表页很常用)
你可以再做一个 primaryBtnSmall(),高度 36、字号 14,复用思路一致。
8. 最后给你一句“像人写的总结”
按钮样式这种东西,写一遍看着没啥,但项目一大就会发现: 统一按钮规范 = 省下最多的维护时间。
尤其是 pressed / focused / disabled 这三种状态, 你如果不用 stateStyles 去统一,而是到处手写 onTouch/onFocus,后面改版基本等于灾难。