鸿蒙实战:从零开发响应式计数器应用(HarmonyOS NEXT + ArkTS + ArkUI)
前言
对于刚接触鸿蒙开发的小伙伴来说,Hello World 只是入门第一步。想要真正理解 ArkUI 声明式 UI、响应式状态管理、组件事件交互,计数器绝对是性价比极高的练手项目。
本文基于 HarmonyOS NEXT 系统,使用 DevEco Studio、ArkTS + ArkUI 技术栈,从空白模板出发,一步步实现带加减、归零、文字颜色联动、过渡动画的计数器应用。同时记录开发中遇到的命名冲突踩坑问题,新手可以直接避坑。
一、项目需求与整体目标
本次开发的计数器功能简洁实用,核心需求如下:
看似简单的功能,却覆盖了鸿蒙 UI 开发 **@State 响应式状态、布局组件、事件绑定、动态样式、动画 ** 五大核心知识点,非常适合入门学习。
二、项目结构解析
打开 DevEco Studio,新建项目,选择 Empty Ability 空白模板、Stage 应用模型,生成标准鸿蒙工程目录,下面对核心目录与文件做解读:
plaintext
项目名/
├── AppScope/ # 应用全局配置目录
│ ├── app.json5 # 应用包名、厂商、版本等基础配置
│ └── resources/ # 全局资源:应用图标、启动页等
├── entry/ # 主业务模块(核心代码全部在这里)
│ ├── build-profile.json5 # 模块构建配置
│ ├── hvigorfile.ts # 编译构建脚本
│ └── src/main/
│ ├── ets/
│ │ ├── entryability/
│ │ │ └── EntryAbility.ets # 应用入口Ability,生命周期管理
│ │ └── pages/
│ │ └── Index.ets # 首页页面组件(本次开发核心文件)
│ ├── module.json5 # 模块声明、页面路由配置
│ └── resources/ # 模块级资源:颜色、字符串、图片、路由
│ ├── base/ # 浅色模式资源
│ └── dark/ # 深色模式资源
├── build-profile.json5 # 工程级全局构建配置
├── oh-package.json5 # 项目依赖配置(类似前端 package.json)
└── hvigor/ # HVigor 构建工具配置目录
2.1 应用入口:EntryAbility.ets
应用启动后,会优先执行 EntryAbility.ets,在 onWindowStageCreate 生命周期函数中加载首页页面,是鸿蒙应用的入口调度文件。
import window from '@ohos.window';
import hilog from '@ohos.hilog';
const DOMAIN = 0xFF00;
const TAG = 'CounterDemo';
export default class EntryAbility extends UIAbility {
// 窗口创建完成,加载首页页面
onWindowStageCreate(windowStage: window.WindowStage): void {
// 加载 pages/Index 页面,无需添加 .ets 后缀
windowStage.loadContent('pages/Index', (err) => {
if (err.code) {
hilog.error(DOMAIN, TAG, '页面加载失败:%{public}s', JSON.stringify(err));
return;
}
hilog.info(DOMAIN, TAG, '页面加载成功');
});
}
// 窗口销毁,可在此做资源释放
onWindowStageDestroy(): void {
}
}
关键说明:windowStage.loadContent(‘pages/Index’) 会匹配 ets/pages/Index.ets 文件,文件内被 @Entry 修饰的组件,会渲染为手机可视页面。
2.2 资源分层设计
鸿蒙工程对资源做了清晰分层,职责划分明确:
AppScope/resources:全局应用资源,比如应用桌面图标,作用于整个 App;
entry/src/main/resources:模块级资源,页面配色、文字、路由等业务相关资源统一存放。
分层设计便于项目维护、主题适配与多人协作。
三、方案设计
3.1 响应式状态设计
整个计数器只需要维护一个状态变量:当前计数值 count。
使用鸿蒙专属装饰器 @State 声明为响应式变量:
typescript
运行
@State count: number = 0;
原理:ArkUI 响应式系统会自动监听 @State 变量,一旦数值发生修改,所有依赖该变量的 UI 组件会自动局部刷新,无需手动调用刷新方法。
3.2 页面组件树设计
采用 Column 垂直布局 + Row 水平布局 组合搭建页面,整体结构如下:
plaintext
Column(全屏垂直布局)
├─ Text 标题:计数器
├─ Column(数字展示容器)
│ └─ Text 动态数字(颜色、动画联动)
├─ Row(水平布局)
│ ├─ 减号按钮(红色)
│ └─ 加号按钮(蓝色)
└─ 归零按钮(灰色)
四、完整代码实现
4.1 核心页面 Index.ets(业务主文件)
这是本次开发的核心文件,包含布局、样式、事件、动态颜色、过渡动画全部逻辑:
@Entry
@Component
struct Index {
// 声明响应式状态:计数器数值,初始值为 0
@State count: number = 0;
build() {
// 根布局:垂直布局,铺满全屏并居中
Column() {
// 页面标题
Text('计数器')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.fontColor('#FF409EFF')
.margin({ bottom: 40 })
// 数字展示区域
Column() {
Text(this.count.toString())
.fontSize(72)
.fontWeight(FontWeight.Bold)
// 三目运算符实现动态文字颜色
.fontColor(
this.count > 0 ? '#FF409EFF' // 正数:蓝色
: this.count < 0 ? '#FFFF4757' // 负数:红色
: '#FF333333' // 零:深灰色
)
// 200ms 过渡动画
.animation({ duration: 200 })
}
.width(200)
.height(200)
.backgroundColor('#FFF5F5F5')
.borderRadius(20)
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
.margin({ bottom: 40 })
// 加减按钮行(水平布局)
Row() {
// 减号按钮
Button('−')
.width(80)
.height(80)
.fontSize(36)
.fontWeight(FontWeight.Bold)
.backgroundColor('#FFFF4757')
.borderRadius(40)
.onClick(() => {
this.count--;
})
// 加号按钮
Button('+')
.width(80)
.height(80)
.fontSize(36)
.fontWeight(FontWeight.Bold)
.backgroundColor('#FF409EFF')
.borderRadius(40)
.onClick(() => {
this.count++;
})
}
.width('100%')
.justifyContent(FlexAlign.SpaceEvenly)
.margin({ bottom: 30 })
// 归零按钮
Button('归零')
.width(160)
.height(48)
.fontSize(18)
.fontColor('#FF999999')
.backgroundColor('#FFF0F0F0')
.borderRadius(24)
.onClick(() => {
this.count = 0;
})
}
.width('100%')
.height('100%')
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
.backgroundColor('#FFFFFFFF')
}
}



五、ArkTS & ArkUI 核心语法详解
5.1 @State 响应式状态
@State 是 ArkUI 最基础、最常用的状态装饰器:
被修饰的变量为响应式变量,数据驱动 UI;
变量修改后,框架自动更新关联组件,无需手动刷新;
作用域仅限当前组件内部使用。
对比传统 Android 命令式 UI:不需要调用 invalidate()、setText() 等方法,数据变 UI 自动变,开发效率大幅提升。
5.2 @Entry 与 @Component 装饰器
@Component:标记当前结构体为自定义 UI 组件,是所有组件的基础;
@Entry:标记当前组件为页面入口,应用启动后自动渲染该组件。
两者组合使用,代表这是一个独立页面。
5.3 链式调用语法
ArkUI 采用声明式链式 API,组件样式、事件、布局全部通过 .属性() 连续编写:
Button(‘+’)
.width(80)
.height(80)
.backgroundColor(‘#FF409EFF’)
.onClick(() => { this.count++ })
优势:UI 结构、样式、逻辑代码集中在一处,不用像传统开发那样「布局 XML + 逻辑代码分离」,可读性和维护性更强。
5.4 三目运算符实现动态样式
文本颜色根据数值正负自动切换,直接在行内使用三目表达式判断,简洁高效:
.fontColor(
this.count > 0 ? ‘#FF409EFF’
: this.count < 0 ? ‘#FFFF4757’
: ‘#FF333333’
)
5.5 原生过渡动画
ArkUI 内置动画能力,仅需一行代码即可实现平滑过渡:
.animation({ duration: 200 })
数值、颜色变化时,会在 200ms 内完成过渡,无需引入额外动画库。
六、开发踩坑:组件命名冲突(新手必看)
6.1 问题现象
初期我将页面结构体命名为 struct Counter,编译后直接报错:
plaintext
- Cannot redeclare block-scoped variable ‘Counter’
- The struct name cannot contain reserved tag name: ‘Counter’
- The struct ‘Counter’ cannot have the same name as the built-in component ‘Counter’
6.2 问题原因
Counter 是 ArkUI 框架内置保留组件名,和 Text、Button、Column 一样属于系统关键字。自定义组件名不能和框架内置组件重名,否则触发编译冲突。
6.3 解决方案
规避系统保留关键字,修改结构体名称即可:
diff
- struct Counter {
- struct Index {
修改后重新编译,项目正常运行。
避坑总结:自定义组件、变量命名,尽量避开 Text/Button/Column/Row/Counter 等系统内置组件名。
七、运行效果
点击蓝色「+」按钮:数字递增,文字显示蓝色;
点击红色「-」按钮:数字递减,负数文字显示红色;
点击灰色「归零」按钮:数字重置为 0,文字变为深灰色;
所有数值变化,均带有 200ms 平滑过渡动画。
八、知识点总结
8.1 鸿蒙应用分层架构
本次项目主要使用最上层两大模块:
plaintext
UI层(ArkTS + ArkUI) → 页面布局、组件、交互、状态
Ability层(UIAbility) → 应用生命周期、页面加载调度
服务层 → 系统能力API调用
内核层 → 鸿蒙系统内核
8.2 声明式 UI vs 传统命令式 UI
8.3 本次用到核心组件与语法
布局组件:Column 垂直布局、Row 水平布局
基础组件:Text 文本、Button 按钮
核心装饰器:@Entry、@Component、@State
常用能力:onClick 点击事件、animation 过渡动画、三目动态样式
九、项目扩展方向(进阶练习)
基础计数器功能简单,可基于现有代码继续拓展,提升实战能力:
自定义步长:增加 +5、-10 快捷按钮,支持自定义步长;
操作历史记录:使用 List 组件记录每一次加减操作与时间;
数据持久化:借助 Preferences 本地存储,重启应用保留计数值;
动画增强:给数字添加缩放、抖动动画,提升交互质感;
深色模式适配:配置深色模式资源,自动跟随系统主题切换配色。
十、文件清单
整个项目仅需修改一个核心业务文件,模板自带文件无需改动:
entry/src/main/ets/pages/Index.ets:计数器核心代码(主文件)
entry/src/main/ets/entryability/EntryAbility.ets:应用入口(默认模板,无修改)
结语
计数器虽然是入门级项目,但吃透它,就掌握了鸿蒙 ArkUI 开发状态管理、布局、事件、动态样式四大基石。后续开发复杂页面、功能组件,都是在这些基础知识点上延伸。
如果你也是鸿蒙初学者,建议亲手敲一遍代码,结合本文踩坑点规避问题,快速上手鸿蒙应用开发。
更多推荐


所有评论(0)