第1章:ArkUI声明式UI基础
各位同学,咱们开始进入正题。
ArkUI 是鸿蒙原生开发的 UI 框架。说白了,它就是用来画界面的。你看到的按钮、文字、输入框,都是用它搭出来的。我刚开始接触 ArkUI 时,第一反应是——这不就是 Flutter 吗?嗯,确实有相似之处,但细节上差别不小。
1.1 声明式UI:换个思路写界面
传统开发里,我们写界面通常是这样的:
- 先创建一个布局文件
- 然后在代码里找到控件
- 再手动更新它的属性
这叫「命令式 UI」。你告诉系统每一步该怎么做。
ArkUI 不一样。它是「声明式 UI」。你只需要描述界面「长什么样」,系统会自动帮你搞定更新。举个例子:
@State message: string = 'Hello, HarmonyOS!'
build() {
Column() {
Text(this.message)
.fontSize(30)
.fontWeight(FontWeight.Bold)
Button('点击修改')
.onClick(() => {
this.message = '你点了我一下'
})
}
}
看到没?我只需要声明一个 message 变量,然后在 Text 组件里引用它。当按钮被点击时,我直接修改 message 的值,界面就自动刷新了。不需要手动调用 setText() 之类的方法。
核心思想:UI 是状态的一个函数。状态变了,UI 自动跟着变。
1.2 基础组件:Text、Button、Image、TextInput
这几个组件,你写任何 App 都绕不开。我一个个说。
Text — 显示文字
最常用的组件,没有之一。用法很简单:
Text('这是一段文字')
.fontSize(16)
.fontColor(Color.Blue)
.textAlign(TextAlign.Center)
我在项目中遇到过一个问题:文字太长被截断了。后来发现加个 .maxLines(2) 和 .textOverflow(TextOverflow.Ellipsis) 就能优雅地显示省略号。
Button — 按钮
用户交互的核心。ArkUI 的 Button 支持多种样式:
Button('默认按钮')
.onClick(() => {
console.info('按钮被点击了')
})
Button('圆角按钮')
.borderRadius(20)
.backgroundColor('#007AFF')
Button('带图标的按钮')
.type(ButtonType.Normal)
.icon($r('app.media.icon_star'))
嗯,这里要注意:onClick 是点击事件,别写成 onClick() 带括号,那是调用函数,不是绑定事件。我刚开始就犯过这个错。
Image — 图片
显示图片,支持本地资源和网络图片:
// 本地图片
Image($r('app.media.logo'))
.width(100)
.height(100)
// 网络图片
Image('https://example.com/photo.png')
.objectFit(ImageFit.Cover)
你想想看,网络图片加载失败怎么办?ArkUI 提供了 .alt() 方法设置占位图:
Image('https://example.com/photo.png')
.alt($r('app.media.placeholder'))
小技巧:本地图片放在 resources/base/media 目录下,用 $r() 引用。别直接写路径字符串,那样容易出错。
TextInput — 文本输入框
用户输入信息的地方。登录注册页面必备:
@State inputValue: string = ''
build() {
TextInput({ placeholder: '请输入用户名', text: this.inputValue })
.onChange((value: string) => {
this.inputValue = value
})
.maxLength(20)
.type(InputType.Normal)
}
我曾经踩过一个坑:密码输入框忘记设置 .type(InputType.Password),结果用户输入的密码明文显示在屏幕上。嗯,这种低级错误,希望大家别犯。
1.3 @State 装饰器:状态驱动的核心
这是 ArkUI 最核心的概念。没有它,声明式 UI 就玩不转。
@State 的作用很简单:标记一个变量为「响应式状态」。当这个变量的值发生变化时,所有依赖它的 UI 组件都会自动重新渲染。
看个完整例子:
@Entry
@Component
struct CounterPage {
@State count: number = 0
build() {
Column() {
Text(`当前计数: ${this.count}`)
.fontSize(24)
Row() {
Button('+1')
.onClick(() => {
this.count++
})
Button('-1')
.onClick(() => {
this.count--
})
}
}
}
}
为什么点击按钮后,Text 会自动更新?因为 count 被 @State 装饰了。ArkUI 框架会监听它的变化,一旦改变,就通知 UI 重新渲染。
重要提醒:只有被 @State 装饰的变量才能触发 UI 更新。普通变量改了,界面不会变。我见过有人写了半天,发现界面死活不刷新,最后发现忘了加 @State。
1.4 状态驱动的更新机制
咱们深入一点。ArkUI 的状态更新机制,其实是一个「观察者模式」的变体。
流程是这样的:
- 你用
@State声明了一个变量 - ArkUI 框架自动为这个变量建立「依赖追踪」
- 当变量变化时,框架会找到所有「依赖」这个变量的 UI 组件
- 只重新渲染这些组件,其他不变
说白了,就是「精准打击」。不会因为一个状态变了,整个页面都重绘。性能上比传统方式好很多。
我建议你记住一个原则:能用 @State 解决的问题,别用全局变量。全局变量虽然方便,但没法触发 UI 更新,而且容易造成代码耦合。
1.5 实战:写一个登录表单
光说不练假把式。咱们把今天学的知识串起来,写一个简单的登录界面:
@Entry
@Component
struct LoginPage {
@State username: string = ''
@State password: string = ''
@State isLogging: boolean = false
build() {
Column() {
// 标题
Text('欢迎登录')
.fontSize(28)
.fontWeight(FontWeight.Bold)
.margin({ bottom: 40 })
// 用户名输入
TextInput({ placeholder: '请输入用户名' })
.onChange((value) => {
this.username = value
})
.margin({ bottom: 16 })
// 密码输入
TextInput({ placeholder: '请输入密码' })
.type(InputType.Password)
.onChange((value) => {
this.password = value
})
.margin({ bottom: 32 })
// 登录按钮
Button('登录')
.width('100%')
.onClick(() => {
this.isLogging = true
// 这里可以调用登录接口
console.info(`用户名: ${this.username}, 密码: ${this.password}`)
})
}
.padding(24)
.width('100%')
.height('100%')
}
}
这个例子包含了 Text、TextInput、Button 三个组件,以及 @State 状态管理。你把它跑起来,输入内容,点击按钮,看看控制台输出。嗯,这就是 ArkUI 声明式开发的基本套路。
1.6 本章小结
咱们今天聊了这些:
- 声明式 UI 是什么——描述界面,而不是命令界面
- 四个基础组件——Text、Button、Image、TextInput
- @State 装饰器——让变量变成响应式
- 状态驱动机制——状态变了,UI 自动更新
下一章,咱们会深入布局系统,看看 Row、Column、Stack 这些容器组件怎么用。到时候你会发现,掌握了这些基础,写复杂界面其实也不难。
好,今天就到这儿。动手写写代码,比看十遍文章都管用。