HarmonyOS应用开发实战:猫猫大作战-样式抽成可复用类,一处定义、多处复用,还能针对不同状态(正常/按下/禁用)应用不同样式
前言回顾「猫猫大作战」的按钮——「开始游戏」绿、「暂停」灰、「重新开始」红、「再来一局」绿、「返回主菜单」浅灰。每个按钮都重复写了width/height/fontSize/borderRadius这堆属性代码重复严重改一处要改 N 处。HarmonyOS 提供了AttributeModifier属性修饰器——把样式抽成可复用类一处定义、多处复用还能针对不同状态正常/按下/禁用应用不同样式。本篇以「猫猫大作战」按钮样式复用为锚点把 AttributeModifier 的定义与复用、多状态样式、与 Styles/Extend 的取舍三大要点讲透。提示本系列不讲 ArkTS 基础语法与环境搭建假设你已跟完第 1–29 篇。本篇是布局进阶的收尾篇。一、场景拆解按钮样式重复回顾「猫猫大作战」底部栏按钮第 19 篇// 来源entry/src/main/ets/pages/Index.ets GameView() 底部栏 Button(暂停) .width(100).height(44) .fontSize(15).fontColor(#FFFFFF) .backgroundColor(#95A5A6) .borderRadius(22) .onClick(() { this.pauseGame(); }) Button(重新开始) .width(100).height(44) .fontSize(15).fontColor(#FFFFFF) .backgroundColor(#E74C3C) .borderRadius(22) .onClick(() { this.clearTimers(); this.startGame(); })痛点问题表现重复代码width(100).height(44).fontSize(15)...每个按钮写一遍改一处动全身按钮高度 44 改 48要全文搜索替换多状态难管按下/禁用样式要 onTouch 手动切代码冗长AttributeModifier 的解法// 1. 定义样式类 class SecondaryButtonModifier implements AttributeModifierButtonAttribute { applyNormalAttribute(instance: ButtonAttribute): void { instance.width(100).height(44).fontSize(15) .fontColor(#FFFFFF).backgroundColor(#95A5A6).borderRadius(22) } } // 2. 复用 Button(暂停).attributeModifier(new SecondaryButtonModifier())关键经验AttributeModifier 把样式抽成类一处定义多处复用。二、AttributeModifier 基本用法2.1 定义样式类class PrimaryButtonModifier implements AttributeModifierButtonAttribute { applyNormalAttribute(instance: ButtonAttribute): void { instance .width(70%) .height(56) .fontSize(20) .fontWeight(FontWeight.Bold) .fontColor(#FFFFFF) .backgroundColor(#2ECC71) .borderRadius(28) .shadow({ radius: 8, color: rgba(46, 204, 113, 0.4), offsetY: 4 }) } }核心要素要素说明implements AttributeModifierButtonAttribute泛型指定目标组件类型applyNormalAttribute(instance)正常状态应用样式instance.width(...)链式调用与组件属性一致2.2 应用样式Button($r(app.string.start_game)) .attributeModifier(new PrimaryButtonModifier()) .onClick(() { this.startGame(); })关键经验.attributeModifier(new XxxModifier())一行应用全套样式。2.3 三种按钮样式类// 主操作按钮绿色开始游戏 class PrimaryButtonModifier implements AttributeModifierButtonAttribute { applyNormalAttribute(instance: ButtonAttribute): void { instance .width(70%).height(56) .fontSize(20).fontWeight(FontWeight.Bold) .fontColor(#FFFFFF).backgroundColor(#2ECC71) .borderRadius(28) .shadow({ radius: 8, color: rgba(46, 204, 113, 0.4), offsetY: 4 }) } } // 次要操作按钮灰色暂停 class SecondaryButtonModifier implements AttributeModifierButtonAttribute { applyNormalAttribute(instance: ButtonAttribute): void { instance .width(100).height(44) .fontSize(15).fontColor(#FFFFFF) .backgroundColor(#95A5A6).borderRadius(22) } } // 危险操作按钮红色重新开始 class DangerButtonModifier implements AttributeModifierButtonAttribute { applyNormalAttribute(instance: ButtonAttribute): void { instance .width(100).height(44) .fontSize(15).fontColor(#FFFFFF) .backgroundColor(#E74C3C).borderRadius(22) } }三、多状态样式3.1 applyPressedAttribute 按下状态class PrimaryButtonModifier implements AttributeModifierButtonAttribute { applyNormalAttribute(instance: ButtonAttribute): void { instance.backgroundColor(#2ECC71) // 正常亮绿 } applyPressedAttribute(instance: ButtonAttribute): void { instance.backgroundColor(#27AE60) // 按下深绿 } }状态回调对照回调触发时机适用applyNormalAttribute正常显示默认样式applyPressedAttribute按下时按压反馈applyDisabledAttributeenabled(false)时禁用样式applyFocusedAttribute获得焦点时键盘/遥控器焦点applySelectedAttribute选中态Toggle/Tab3.2 禁用状态样式class SubmitButtonModifier implements AttributeModifierButtonAttribute { applyNormalAttribute(instance: ButtonAttribute): void { instance.backgroundColor(#2ECC71).fontColor(#FFFFFF) } applyDisabledAttribute(instance: ButtonAttribute): void { instance.backgroundColor(#BDC3C7).fontColor(#ECF0F1) // 灰色禁用 } } // 使用禁用态自动应用 applyDisabledAttribute Button(提交).attributeModifier(new SubmitButtonModifier()).enabled(this.isFormValid)3.3 完整多状态按钮class FullStateButtonModifier implements AttributeModifierButtonAttribute { applyNormalAttribute(instance: ButtonAttribute): void { instance .width(200).height(48) .fontSize(16).fontWeight(FontWeight.Bold) .fontColor(#FFFFFF) .backgroundColor(#2ECC71) .borderRadius(24) } applyPressedAttribute(instance: ButtonAttribute): void { instance.backgroundColor(#27AE60) // 按下深绿 instance.scale({ x: 0.95, y: 0.95 }) // 按下缩小 5% } applyDisabledAttribute(instance: ButtonAttribute): void { instance.backgroundColor(#BDC3C7) // 禁用灰 instance.fontColor(#ECF0F1) } }执行流程正常显示 →applyNormalAttribute用户按下 →applyPressedAttribute覆盖 normal 的差异属性用户松开 → 回到applyNormalAttributeenabled(false)→applyDisabledAttribute四、改造底部栏用 AttributeModifier4.1 定义三个按钮样式类// 次要按钮暂停 class SecondaryButtonModifier implements AttributeModifierButtonAttribute { applyNormalAttribute(instance: ButtonAttribute): void { instance .width(100).height(44) .fontSize(15).fontColor(#FFFFFF) .backgroundColor(#95A5A6).borderRadius(22) } applyPressedAttribute(instance: ButtonAttribute): void { instance.backgroundColor(#7F8C8D) // 按下深灰 } } // 危险按钮重新开始 class DangerButtonModifier implements AttributeModifierButtonAttribute { applyNormalAttribute(instance: ButtonAttribute): void { instance .width(100).height(44) .fontSize(15).fontColor(#FFFFFF) .backgroundColor(#E74C3C).borderRadius(22) } applyPressedAttribute(instance: ButtonAttribute): void { instance.backgroundColor(#C0392B) // 按下深红 } }4.2 改造底部栏Builder GameView() { Column() { this.GameHUD() Column() { // 预告区 Row() { /* ... */ } // 游戏棋盘 Stack() { /* 3 层叠 */ } .width(GameConfig.BOARD_WIDTH * GameConfig.CELL_SIZE) .height(GameConfig.BOARD_HEIGHT * GameConfig.CELL_SIZE) .borderRadius(12) .clip(true) .backgroundColor(#D6EEF5) } .alignItems(HorizontalAlign.Center) Spacer() // 弹性占位推底部栏到最底 // 底部控制栏AttributeModifier 改造 Row() { Button($r(app.string.pause)) .attributeModifier(new SecondaryButtonModifier()) .onClick(() { this.pauseGame(); }) Spacer() // 撑开两按钮到两端 Button($r(app.string.restart)) .attributeModifier(new DangerButtonModifier()) .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) }改造对比维度原版属性堆叠AttributeModifier 版代码量每按钮 7 行属性每按钮 1 行 modifier按压反馈无默认 stateEffectapplyPressedAttribute 自定义改样式改每个按钮的属性改 Modifier 类全应用生效复用无法复用一处定义多处用五、AttributeModifier vs Styles vs ExtendArkUI 有三种样式复用机制5.1 Styles 通用样式Styles function primaryButtonStyle() { .width(70%).height(56) .fontSize(20).fontWeight(FontWeight.Bold) } Button(开始).primaryButtonStyle()5.2 Extend 特定组件样式Extend(Button) function primaryButtonExtend() { .width(70%).height(56) .backgroundColor(#2ECC71).borderRadius(28) } Button(开始).primaryButtonExtend()5.3 三者对比机制适用组件多状态跨组件复用推荐Styles任意❌✅简单通用样式Extend指定组件❌❌特定组件样式AttributeModifier任意✅✅复杂多状态样式实战经验简单样式用 Styles特定组件用 Extend多状态/复杂复用用 AttributeModifier。5.4 选择决策树样式需要多状态按下/禁用 ├─ 是 → AttributeModifier └─ 否 └─ 样式跨多种组件复用 ├─ 是 → Styles └─ 否 └─ 样式只针对某组件 → Extend六、踩坑提示6.1 AttributeModifier 泛型不匹配// ❌ 错误Modifier 声明 ButtonAttribute但用在 Text 上 class MyModifier implements AttributeModifierButtonAttribute { /* ... */ } Text(A).attributeModifier(new MyModifier()) // 类型不匹配 // ✅ 正确泛型与组件匹配 class MyModifier implements AttributeModifierTextAttribute { /* ... */ } Text(A).attributeModifier(new MyModifier())6.2 忘记 implements AttributeModifier// ❌ 错误没 implementsattributeModifier 不接受 class MyModifier { applyNormalAttribute() {} } // ✅ 正确implements AttributeModifierT class MyModifier implements AttributeModifierButtonAttribute { /* ... */ }6.3 Modifier 与组件属性冲突// ⚠️ Modifier 设了 backgroundColor组件又设了一次后者覆盖前者 Button(A) .attributeModifier(new MyModifier()) // 设 backgroundColor(#2ECC71) .backgroundColor(#E74C3C) // 覆盖 Modifier 的绿色 // ✅ 推荐样式统一在 Modifier 里管组件只设业务属性 Button(A) .attributeModifier(new MyModifier()) .onClick(() { /* ... */ })6.4 applyPressedAttribute 没覆盖 normal 的所有差异class MyModifier implements AttributeModifierButtonAttribute { applyNormalAttribute(instance: ButtonAttribute): void { instance.backgroundColor(#2ECC71).scale({ x: 1, y: 1 }) } applyPressedAttribute(instance: ButtonAttribute): void { instance.backgroundColor(#27AE60) // 只改了颜色scale 还是 1 // 想要按下缩小要显式设 scale instance.scale({ x: 0.95, y: 0.95 }) } }七、调试技巧临时加console.info在 applyNormalAttribute 里追样式应用时机。按压无反馈检查是否实现了applyPressedAttribute检查组件是否enabled(false)。样式不生效检查 Modifier 泛型是否与组件匹配检查是否被组件属性覆盖。多 Modifier 冲突一个组件只能用一个attributeModifier多个样式要合并到一个 Modifier 类。八、性能与最佳实践复杂多状态样式用 AttributeModifier——一处定义多处复用。泛型与组件匹配——ButtonAttribute 配 ButtonTextAttribute 配 Text。样式统一在 Modifier 管——组件只设业务属性onClick、state。简单通用样式用 Styles——AttributeModifier 杀鸡用牛刀。状态回调全覆盖——normal/pressed/disabled 都实现避免状态残留。Modifier 类可继承复用——class PrimaryModifier extends BaseModifier。九、阶段一收尾UI 组件与布局实战总结1-30本篇是阶段一「UI 组件与布局实战1-30」的收尾篇。回顾阶段一完整覆盖篇主题核心组件1-5主菜单排版Text、Button、Spacer、Column6-10主菜单视觉linearGradient、justifyContent、Row、Stack、if/else11-12游戏页 HUD 预告GameHUD、Circle 预告13-14棋盘背景ForEach 双层循环、隔行变色15-16猫咪渲染Emoji Text、Circle 背景、position 绝对定位17列点击层透明 onClick 覆盖层18-19底部控制栏Row 双按钮、Button 颜色与圆角20SymbolGlyph系统符号字体替代 Emoji21RelativeContainer扁平复杂布局22Blank替代 Spacer 的间距23layoutWeight按比例分配宽度24displayPriority窄屏自适应隐藏25Scroller长内容滚动容器26Badge消息角标27Image 资源$r 与 $rawfile28暗色模式深色资源与 colorMode29多语言 i18nstring.json 多语言30本篇AttributeModifier按钮样式复用阶段一核心收获ArkUI 声明式 UI组件 属性 事件三件套。布局容器Column/Row/Stack/RelativeContainer 四大布局。状态驱动State 改变 → build() 重渲染。资源系统$r 编译期资源 $rawfile 原始文件。多端适配暗色模式、多语言、多分辨率。样式复用Styles/Extend/AttributeModifier 三层方案。接下来阶段二31-70将进入状态管理 交互 动画深水区State/Link/Provide/Consume 状态管理、Watch 监听、setInterval 主循环、animateTo 显式动画、Reusable 列表复用、LazyForEach 大列表等。总结本篇我们从 AttributeModifier 切入掌握了样式类定义与复用、多状态样式normal/pressed/disabled、与 Styles/Extend 的取舍三大要点并给出了底部栏 AttributeModifier 改造完整代码。核心要点AttributeModifier 一处定义多处复用多状态用 applyPressedAttribute 等泛型与组件匹配。下一篇我们将进入阶段二拆解 State 单组件状态——得分驱动 UI。如果这篇文章对你有帮助欢迎点赞、收藏⭐、关注你的支持是我持续创作的动力相关资源「猫猫大作战」项目源码本仓库entry/src/main/ets/pages/Index.etsAttributeModifier 属性修饰器官方指南Styles 样式复用官方指南Extend 扩展官方指南ArkUI 样式复用最佳实践开源鸿蒙跨平台社区HarmonyOS 开发者官方文档首页系列索引本仓库articles/INDEX.md

相关新闻

AI Agent 面试题 568:如何实现多Agent系统的Agent健康监控?

AI Agent 面试题 568:如何实现多Agent系统的Agent健康监控?

🔥 AI Agent 面试题 568:如何实现多Agent系统的Agent健康监控?摘要:本文深入解析了「如何实现多Agent系统的Agent健康监控?」这一 AI Agent 领域的核心面试题。文章从 群体智能 的基本概念出发,系统性地剖析…

2026/7/28 1:25:10 阅读更多 →
挑选北京 GEO 服务商不再盲目!十强合规团队能力剖析,覆盖各行各业需求

挑选北京 GEO 服务商不再盲目!十强合规团队能力剖析,覆盖各行各业需求

专业北京中关村珐恩AIGEO知识友好评估报告一、GEO赛道现状与珐恩AI的行业定位2026年,生成式引擎优化(Generative Engine Optimization,GEO)已成为企业数字营销核心赛道。中国信通院《人工智能发展白皮书》指出,90%中小…

2026/7/28 1:25:10 阅读更多 →
2026 北京地理优化服务商调研:十家合规团队实力解析,垂直行业采购参考

2026 北京地理优化服务商调研:十家合规团队实力解析,垂直行业采购参考

专业北京中关村珐恩AIGEO解决方案行业洞察生成式引擎优化(GEO) 正从概念走向企业主流刚需。当ChatGPT、豆包、DeepSeek等AI搜索渠道开始每天影响数亿条商业决策时,“我的品牌在AI里查无此人”已经成为企业最隐蔽的流量危机。本文将结合30细分…

2026/7/28 1:25:10 阅读更多 →

最新新闻

DeepSeek V4 API成本优化:高峰时段价格策略与实战方案

DeepSeek V4 API成本优化:高峰时段价格策略与实战方案

DeepSeek V4 API 高峰时段价格策略分析与成本优化实战 在AI应用开发过程中,很多开发者都遇到过这样的困扰:白天调用API响应迅速、成本可控,但到了晚上或特定时段,不仅响应变慢,费用还明显上涨。特别是使用DeepSeek V4这类高性能模型时,价格波动对项目预算影响显著。本文将…

2026/7/28 1:34:14 阅读更多 →
深度解析CFC项目:基于cimbar编码的视觉数据传输技术架构

深度解析CFC项目:基于cimbar编码的视觉数据传输技术架构

深度解析CFC项目:基于cimbar编码的视觉数据传输技术架构 【免费下载链接】cfc Demo/test android app for libcimbar. Copy files over the cell phone camera! 项目地址: https://gitcode.com/gh_mirrors/cfc/cfc CameraFileCopy(CFC&#xff09…

2026/7/28 1:34:14 阅读更多 →
如何快速下载国家中小学智慧教育平台电子课本:3分钟搞定PDF教材的完整教程

如何快速下载国家中小学智慧教育平台电子课本:3分钟搞定PDF教材的完整教程

如何快速下载国家中小学智慧教育平台电子课本:3分钟搞定PDF教材的完整教程 【免费下载链接】tchMaterial-parser 国家中小学智慧教育平台 电子课本下载工具,帮助您从智慧教育平台中获取电子课本的 PDF 文件网址并进行下载,让您更方便地获取课…

2026/7/28 1:34:14 阅读更多 →
深度观察 | 2026 木门十大品牌排行榜发布:头部品牌凭实力赢得市场认可

深度观察 | 2026 木门十大品牌排行榜发布:头部品牌凭实力赢得市场认可

行业背景与榜单说明 2026 年,中国木门行业步入高质量发展的深度调整期。随着存量房翻新、改善型住房需求持续释放,叠加绿色家居、全屋定制相关政策的推动,国内木门市场规模保持稳步增长。与此同时,消费需求已从基础的空间遮隔功能…

2026/7/28 1:34:14 阅读更多 →
小学信息科技教学资源开发与实践指南

小学信息科技教学资源开发与实践指南

1. 项目背景与核心价值这套义务教育版小学信息科技全套资料的出现,填补了基础教育阶段系统性教学资源的空白。作为一线教师,我深刻体会到优质教学资源对课堂效率的提升作用。这套资料严格对标国家课程标准,覆盖3-6年级全学段,包含…

2026/7/28 1:34:14 阅读更多 →
【新】5p242基于机器学习的农产品价格数据分析与预测可视化系统31(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_

【新】5p242基于机器学习的农产品价格数据分析与预测可视化系统31(设计源文件+万字报告+讲解)(支持资料、图片参考_相关定制)_

【新】5p242基于机器学习的农产品价格数据分析与预测可视化系统31(设计源文件万字报告讲解)(支持资料、图片参考_相关定制)_ python3.8hadoopdjangospidermysql5.7vue 系统采用Scrapy框架进行数据采集,从惠农网等平台抓取蔬菜、水产品等农产品…

2026/7/28 1:33:13 阅读更多 →

日新闻

告别臃肿!3步让你的暗影精灵笔记本重获新生

告别臃肿!3步让你的暗影精灵笔记本重获新生

告别臃肿!3步让你的暗影精灵笔记本重获新生 【免费下载链接】OmenSuperHub Control Omen laptop performance, fan speeds, and keyboard lighting, and unlock power limits. 项目地址: https://gitcode.com/gh_mirrors/om/OmenSuperHub 你是否也曾为官方Om…

2026/7/28 0:00:43 阅读更多 →
RAG必踩坑!财报法规检索不准?这款开源工具让答案浮出水面,准确率飙升98.7%!

RAG必踩坑!财报法规检索不准?这款开源工具让答案浮出水面,准确率飙升98.7%!

做 RAG 的人应该都踩过这个致命的坑:把几百页的财报、法规、技术手册扔给向量库,问一个具体问题,搜出来的全是沾边但没用的内容 —— 关键信息要么被硬切块拆碎了,要么藏在几十条结果的最下面。语义相似≠真正相关,这个…

2026/7/28 0:00:43 阅读更多 →
抖音视频文案提取工具全指南:免费2026版、手机App、在线工具一网打尽

抖音视频文案提取工具全指南:免费2026版、手机App、在线工具一网打尽

2026年做短视频运营,从抖音上扒文案早就不是偷偷抄笔记的事了。我刚开始做内容的时候,每天刷半小时抖音,手动把爆款视频的口播敲进备忘录,一条2分钟的视频得花十来分钟,碰到语速快的还要反复回听。后来试了一圈工具&am…

2026/7/28 0:00:43 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/27 4:33:59 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/27 6:31:56 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/27 4:01:12 阅读更多 →

月新闻