Harmony学习之声明式UI开发
Harmony学习之声明式UI开发
一、场景引入
小明在上一篇文章中掌握了ArkTS语言基础,现在他想要构建一个用户登录界面,包含Logo、用户名输入框、密码输入框和登录按钮。他需要了解如何将这些组件按照设计稿进行布局,并设置合适的样式。本篇文章将系统讲解HarmonyOS声明式UI开发的核心概念、常用组件和布局系统,帮助小明快速构建美观的用户界面。
二、声明式UI核心概念
1. 声明式与命令式对比
命令式开发需要逐步指示每个UI元素的创建、属性设置和关系建立:
// 命令式伪代码
const textView = new TextView();
textView.setText("点击计数:0");
button.setOnClickListener(() => {
textView.setText(`点击计数:${++count}`);
});
声明式开发采用反向控制逻辑,UI随数据自动更新:
@Component
struct CounterPage {
@State count: number = 0;
build() {
Column() {
Text(`点击计数:${this.count}`)
Button('增加')
.onClick(() => {
this.count++;
})
}
}
}
2. 核心三要素
| 要素 | 作用 | 典型应用场景 |
|---|---|---|
| 数据驱动 | UI随数据自动更新 | 实时数据展示、表单输入 |
| 组件化 | 高内聚、可复用单元 | 公共控件封装、业务模块拆分 |
| 状态管理 | 跨组件数据同步机制 | 全局配置、用户登录状态 |
三、常用基础组件
1. Text文本组件
Text组件用于显示文本内容,支持丰富的样式设置:
Text('Hello HarmonyOS')
.fontSize(20) // 字体大小
.fontColor('#FF0000') // 字体颜色
.fontWeight(FontWeight.Bold) // 字体粗细
.fontStyle(FontStyle.Italic) // 字体样式
.textAlign(TextAlign.Center) // 文本对齐
.maxLines(1) // 最大行数
.textOverflow({overflow: TextOverflow.Ellipsis}) // 溢出处理
文本对齐方式:
TextAlign.Start:左对齐(默认)TextAlign.Center:居中对齐TextAlign.End:右对齐
文本溢出处理:
TextOverflow.Clip:超出部分裁剪TextOverflow.Ellipsis:超出部分显示省略号
2. Image图片组件
Image组件用于显示图片,支持本地和网络图片:
// 本地图片
Image($r('app.media.logo'))
.width(100)
.height(100)
.objectFit(ImageFit.Contain) // 图片填充模式
// 网络图片
Image('https://example.com/image.jpg')
.width(200)
.height(200)
图片填充模式:
ImageFit.Contain:等比缩放,保持宽高比,可能留白ImageFit.Cover:等比缩放,填充整个容器,可能裁剪ImageFit.Fill:拉伸填充,可能变形
3. Button按钮组件
Button组件用于用户交互:
Button('登录')
.width(300)
.height(50)
.backgroundColor('#007DFF')
.fontColor(Color.White)
.fontSize(18)
.type(ButtonType.Capsule) // 按钮类型
.onClick(() => {
// 点击事件处理
console.log('按钮被点击');
})
按钮类型:
ButtonType.Capsule:胶囊按钮(默认)ButtonType.Normal:矩形按钮ButtonType.Circle:圆形按钮
4. TextInput输入框组件
TextInput用于接收用户输入:
TextInput({ placeholder: '请输入用户名' })
.width('90%')
.height(50)
.backgroundColor(Color.White)
.borderRadius(8)
.type(InputType.Normal) // 输入类型
.onChange((value: string) => {
// 输入内容变化
console.log(value);
})
输入类型:
InputType.Normal:普通文本InputType.Password:密码输入InputType.Email:邮箱输入
四、布局系统
1. Column垂直布局
Column用于垂直排列子组件:
Column({ space: 20 }) { // 子组件间距20vp
Text('顶部')
.fontSize(20)
Text('中间')
.fontSize(20)
Text('底部')
.fontSize(20)
}
.width('100%')
.height('100%')
.alignItems(HorizontalAlign.Center) // 水平居中对齐
.justifyContent(FlexAlign.Center) // 垂直居中对齐
对齐方式:
HorizontalAlign.Start:左对齐HorizontalAlign.Center:居中对齐HorizontalAlign.End:右对齐
2. Row水平布局
Row用于水平排列子组件:
Row({ space: 15 }) { // 子组件间距15vp
Text('左侧')
.layoutWeight(1) // 权重分配
Text('中间')
.layoutWeight(2)
Text('右侧')
.layoutWeight(1)
}
.width('100%')
.height(50)
.justifyContent(FlexAlign.SpaceBetween) // 两端对齐
主轴对齐方式:
FlexAlign.Start:起始位置对齐FlexAlign.Center:居中对齐FlexAlign.End:结束位置对齐FlexAlign.SpaceBetween:两端对齐,中间等距FlexAlign.SpaceAround:等距分布
3. Stack层叠布局
Stack用于层叠显示子组件:
Stack() {
Image($r('app.media.background'))
.width('100%')
.height('100%')
Text('水印文字')
.fontSize(16)
.fontColor('#66000000')
.position({ x: '50%', y: '50%' }) // 绝对定位
}
.width(300)
.height(200)
position定位:
x:水平位置,支持百分比或固定值y:垂直位置,支持百分比或固定值
4. Flex弹性布局
Flex提供更灵活的布局方式:
Flex({ direction: FlexDirection.Row, wrap: FlexWrap.Wrap }) {
Text('项目1')
.flexGrow(1) // 弹性拉伸
.backgroundColor('#F5DEB3')
Text('项目2')
.flexGrow(2)
.backgroundColor('#D2B48C')
Text('项目3')
.flexGrow(1)
.backgroundColor('#F5DEB3')
}
.width('100%')
.height(100)
.justifyContent(FlexAlign.SpaceBetween)
Flex属性:
flexGrow:拉伸比例,剩余空间分配flexShrink:压缩比例,空间不足时压缩flexBasis:基础尺寸
五、通用属性
1. 尺寸设置
Text('示例文本')
.width(200) // 固定宽度
.width('50%') // 百分比宽度
.width('100%') // 占满父容器
.height(100)
.minWidth(100) // 最小宽度
.maxWidth(300) // 最大宽度
2. 边距设置
Text('示例文本')
.margin({ // 外边距
top: 10,
right: 15,
bottom: 10,
left: 15
})
.padding({ // 内边距
top: 5,
right: 10,
bottom: 5,
left: 10
})
3. 背景与边框
Text('示例文本')
.backgroundColor('#F5F5F5') // 背景色
.borderRadius(8) // 圆角
.borderWidth(1) // 边框宽度
.borderColor('#E0E0E0') // 边框颜色
.backgroundImage($r('app.media.bg')) // 背景图片
4. 透明度与可见性
Text('示例文本')
.alpha(0.8) // 透明度,0-1
.visibility(Visibility.Visible) // 可见性
可见性选项:
Visibility.Visible:可见Visibility.Hidden:隐藏但占位Visibility.None:隐藏且不占位
六、实战案例:登录界面
下面是一个完整的登录界面实现:
@Entry
@Component
struct LoginPage {
@State username: string = ''
@State password: string = ''
build() {
Column({ space: 20 }) {
// Logo
Image($r('app.media.logo'))
.width(120)
.height(120)
.margin({ top: 80, bottom: 40 })
// 用户名输入框
Column() {
Text('用户名')
.fontSize(14)
.fontColor('#666666')
.margin({ bottom: 8 })
TextInput({ text: this.username, placeholder: '请输入用户名' })
.width('90%')
.height(50)
.backgroundColor(Color.White)
.borderRadius(8)
.borderWidth(1)
.borderColor('#E0E0E0')
.padding({ left: 15, right: 15 })
.onChange((value: string) => {
this.username = value
})
}
.width('100%')
.padding({ left: 20, right: 20 })
// 密码输入框
Column() {
Text('密码')
.fontSize(14)
.fontColor('#666666')
.margin({ bottom: 8 })
TextInput({ text: this.password, placeholder: '请输入密码' })
.width('90%')
.height(50)
.backgroundColor(Color.White)
.borderRadius(8)
.borderWidth(1)
.borderColor('#E0E0E0')
.padding({ left: 15, right: 15 })
.type(InputType.Password)
.onChange((value: string) => {
this.password = value
})
}
.width('100%')
.padding({ left: 20, right: 20 })
// 登录按钮
Button('登录')
.width('90%')
.height(50)
.backgroundColor('#007DFF')
.fontColor(Color.White)
.fontSize(18)
.margin({ top: 30 })
.onClick(() => {
// 登录逻辑
console.log('用户名:', this.username)
console.log('密码:', this.password)
})
}
.width('100%')
.height('100%')
.backgroundColor('#F5F5F5')
}
}
七、样式复用与优化
1. 使用@Styles装饰器复用样式
@Styles
function primaryButton() {
.width('90%')
.height(50)
.backgroundColor('#007DFF')
.fontColor(Color.White)
.fontSize(18)
.borderRadius(8)
}
// 使用样式
Button('登录')
.primaryButton()
2. 使用@Builder装饰器复用UI片段
@Builder
function inputField(label: string, value: string, isPassword: boolean = false) {
Column() {
Text(label)
.fontSize(14)
.fontColor('#666666')
.margin({ bottom: 8 })
TextInput({ text: value, placeholder: `请输入${label}` })
.width('90%')
.height(50)
.backgroundColor(Color.White)
.borderRadius(8)
.borderWidth(1)
.borderColor('#E0E0E0')
.padding({ left: 15, right: 15 })
.type(isPassword ? InputType.Password : InputType.Normal)
}
.width('100%')
.padding({ left: 20, right: 20 })
}
// 使用Builder
this.inputField('用户名', this.username)
this.inputField('密码', this.password, true)
八、性能优化建议
1. 布局优化
- 减少嵌套层级:避免超过3层嵌套布局
- 使用百分比布局:优先使用百分比而非固定尺寸
- 合理使用Flex:简单布局优先使用Row/Column,复杂布局使用Flex
2. 图片优化
- 使用合适尺寸:避免加载过大图片
- 使用objectFit:合理设置图片填充模式
- 使用占位图:网络图片加载时显示占位图
3. 组件优化
- 组件复用:将可复用的UI封装成自定义组件
- 状态管理:合理使用@State、@Prop、@Link装饰器
- 条件渲染:使用if条件渲染避免不必要的组件渲染
九、总结与行动建议
核心要点回顾
- 声明式UI:采用数据驱动视图的方式,UI随状态自动更新
- 基础组件:掌握Text、Image、Button、TextInput等常用组件
- 布局系统:熟练使用Column、Row、Stack、Flex进行页面布局
- 通用属性:掌握尺寸、边距、背景、边框等样式设置
- 样式复用:使用@Styles和@Builder提高代码复用性
行动建议
- 动手实践:按照本文示例,独立完成登录界面的开发
- 样式调整:尝试修改登录界面的颜色、字体、间距等样式
- 组件扩展:在登录界面基础上添加"记住密码"、"忘记密码"等功能
- 布局练习:使用不同的布局方式实现相同的界面效果
- 查阅文档:遇到问题时,访问华为开发者联盟官网查阅官方文档
通过本篇文章的学习,你已经掌握了HarmonyOS声明式UI开发的核心能力。下一篇文章将深入讲解状态管理,帮助你实现更复杂的交互逻辑和数据同步。

浙公网安备 33010602011771号