HarmonyOS鸿蒙开发 | ArkUI组件与布局
在学习HarmonyOS ArkUI(方舟开发框架)时,整理了一份笔记,方便日后回顾。
本文档为HarmonyOS ArkUI(方舟开发框架)零基础入门学习笔记,基于ArkTS声明式开发范式编写,既适合新手快速上手鸿蒙界面开发,也可作为日常开发的速查手册。
开发环境为HarmonyOS官方开发工具 DevEco Studio 。
一、开发起步
核心开发工具
HarmonyOS界面开发的官方IDE为 DevEco Studio,内置代码编辑器、实时预览器、模拟器等全套开发工具,无需额外配置环境即可快速开发。
- 代码编写:在
build()函数内编写UI构建代码 - 效果查看:通过右侧预览器查看界面效果
声明式UI核心结构
ArkTS声明式开发的核心是自定义组件,页面由一个或多个自定义组件组成。
所有UI结构必须在 build() 函数中声明。
build() 函数有且仅有一个根容器组件,不允许多个同级根元素。
- 基础代码结构模板:
@Entry // 标记这是页面的入口组件 App启动时优先加载
@Component
struct Index {
// 声明状态变量、常量等业务数据
build() {
// 唯一根容器组件
Column() {
// 界面内容:子组件、嵌套容器等
}
// 组件的属性样式 链式调用 建议每个属性独占一行
.width('100%')
.height('100%')
}
}
| 装饰器 | 核心作用 | 使用规则 |
|---|---|---|
@Component | 标记当前结构体为可复用的自定义组件 | 封装UI与逻辑 每个自定义组件必须添加该装饰器 结构体需实现 build()函数 |
@Entry | 标记当前组件为页面入口组件 | 一个页面仅需一个入口组件 预览器会优先渲染该组件 |
二、ArkUI核心思想:组件化布局
ArkUI(方舟开发框架)是鸿蒙官方主推的应用界面构建框架,核心采用组件化的声明式开发思想,所有界面元素都由组件构成,通过组件的组合、嵌套、样式配置完成界面开发。
组件分类
| 组件类型 | 核心作用 | 高频示例 |
|---|---|---|
| 基础组件 | 界面呈现的最小单元,负责内容展示与基础交互 | 文本Text、按钮Button、图片Image、输入框TextInput |
| 容器组件 | 负责子组件的布局排列、尺寸约束,控制界面整体结构 | 列布局Column、行布局Row、列表List、堆叠布局Stack、弹性布局Flex |
标准界面开发流程
遵循「 先排版 → 再填内容 → 最后美化 」的核心思路:
- 拆分界面结构,用容器组件完成整体行列排版,确定页面骨架。
- 在对应容器中放入基础组件,填充文本、图片、按钮等界面内容。
- 通过属性方法为组件设置样式、交互,完成界面美化与功能开发。
三、组件通用属性
通用属性可用于所有组件,用于约束组件尺寸、美化外观、控制位置,是界面开发的基础能力。
核心尺寸单位规范
鸿蒙开发中需严格区分3种核心单位(避免多设备适配异常):
| 单位 | 全称 | 适用场景 | 核心特性 |
|---|---|---|---|
| vp | Virtual Pixel | 组件宽高、内边距、外边距、定位等布局尺寸 | 虚拟像素 会根据设备屏幕密度自动适配 保证不同设备视觉效果一致 是布局首选单位 |
| fp | Font Pixel | 字体大小 | 跟随系统字体大小缩放 兼顾视觉效果与无障碍适配 是字体首选单位 |
| px | Pixel | 仅特殊场景使用 | 设备物理像素点 不同设备分辨率差异大 不推荐直接用于布局 可通过 vp2px()方法将vp转为px |
基础通用属性
| 属性方法 | 作用说明 | 使用规则 |
|---|---|---|
.width(数值) | 设置组件宽度 | 纯数值默认单位为vp 百分比需用单引号包裹 如 .width('100%') 、.width(50) |
.height(数值) | 设置组件高度 | 纯数值默认单位为vp 百分比需用单引号包裹 只设置宽或高另一个维度会按原始比例自动缩放 |
.backgroundColor(颜色值) | 设置组件背景色 | 支持颜色枚举 Color.颜色名支持16进制色值 '#十六进制色号'(16进制必须用单引号包裹) |
.padding(数值/边距对象) | 设置组件内边距 (内容与组件边缘的间距) | 单数值为四边统一内边距 可单独指定边距: .padding({ left: 10, right: 10, top: 5, bottom: 5 }) |
.margin(数值/边距对象) | 设置组件外边距 (组件与其他组件的间距) | 单数值为四边统一外边距 可单独指定边距: .margin({ left: 10, right: 10, top: 5, bottom: 5 })两个相邻组件同时设置外边距则间距会叠加 |
边框 border
-
作用:给组件添加边界,进行装饰美化。
-
支持全方向统一配置和单方向单独配置
// 四个方向统一边框
Text('统一边框')
.border({
width: 1, // 边框宽度(必须设置)
color: '#3274f6', // 边框颜色(不设置则默认为黑色)
style: BorderStyle.Solid // 边框样式(不设置则默认为Solid实线)
})
// 四个方向单独配置边框
Text('单独边框')
.border({
width: { top: 1, left: 2, right: 3, bottom: 1 },
// width设置了哪些方向就有哪些方向的边框
color: { left: Color.Blue, right: Color.Red },
style: { left: BorderStyle.Dashed, right: BorderStyle.Dotted }
})
// 边框样式:Solid实线、Dashed虚线、Dotted点线
圆角 borderRadius
-
作用:设置组件边角弧度
-
支持统一配置和单角单独配置
-
可实现正圆、胶囊按钮等特殊效果
// 四个圆角统一设置
Text('统一圆角')
.borderRadius(5)
// 数值参数指圆的半径,通过不同的数值可以设置不同大小的圆角。
// 圆越大(数值大)则圆角越大 圆越小(数值小)则圆角越小
// 四个角单独设置
Text('单独圆角')
.borderRadius({
topLeft: 5, // 左上角
topRight: 5, // 右上角
bottomLeft: 10, // 左下角
bottomRight: 10 // 右下角
})
// 特殊形状:正圆(宽高必须一致 圆角为宽高的一半)
Text('正圆')
.width(100)
.height(100)
.borderRadius(50) // 圆角是宽或高的一半
.textAlign(TextAlign.Center) // 文本居中显示
// 特殊形状:胶囊按钮(圆角为高度的一半)
Text('胶囊按钮')
.width(150)
.height(50)
.borderRadius(25) // 圆角是高的一半(横状胶囊按钮)
.textAlign(TextAlign.Center) // 文本居中显示
// 竖状胶囊按钮:圆角是宽的一半
// 若同一个组件设置两个borderRadius属性 则新的圆角会覆盖旧的圆角
注意:同一组件重复设置borderRadius,后设置的会覆盖之前的配置。
背景图片相关属性
-
用于给组件添加背景图片
-
支持本地资源与网络资源
-
可控制缩放、位置、平铺效果
| 属性方法 | 作用说明 | 参数 |
|---|---|---|
①.backgroundImage(地址) ② .backgroundImage(地址, 平铺方式) | 设置背景图片源 | 不设置则默认不平铺 ImageRepeat.NoRepeat水平平铺 ImageRepeat.X垂直平铺 ImageRepeat.Y水平垂直均平铺 ImageRepeat.XY |
.backgroundImagePosition(参数) | 调整背景图显示位置 | 支持坐标 { x: 坐标, y: 坐标 }(单位px 可用vp2px()转换为vp)支持枚举 Alignment.Center(居中)等 |
.backgroundImageSize(参数) | 控制背景图缩放 | 支持宽高对象:{ width: 尺寸, height: 尺寸 }宽高设置一边后另一边会自动等比例缩放 支持枚举: ImageSize.Auto 默认原图尺寸ImageSize.Contain 完整显示、不变形、会留白)ImageSize.Cover 铺满容器、不变形、会裁切多余部分) |
Column()
.width('100%')
.height(300)
.backgroundImage($r('app.media.bg'))
.backgroundImageSize(ImageSize.Cover)
.backgroundImagePosition(Alignment.Center)
绝对定位 position
作用:用于自由控制组件位置,可实现层叠效果。
核心特性:
-
参照父组件左上角顶点进行偏移,无父组件则参照页面根容器。
-
绝对定位后的组件不再占用原有布局位置,不影响其他组件的排列。
语法:.position(参数)
Stack() {
// 底层组件
Column()
.width(200)
.height(200)
.backgroundColor('#007DFF')
// 绝对定位的上层组件
Text('定位文本')
.position({ x: 20, y: 20 }) // 水平偏移20vp、垂直偏移20vp
.fontColor(Color.White)
}
.width(300)
.height(300)
// { x : 0, y : 0 }时子组件对应在父组件的左上角(零偏移)
层级控制 zIndex
作用:在不改变组件结构的前提下,调整组件的显示层级。
-
取值为整数数字,数值越大,显示层级越高。
-
默认值为0
Stack() {
Text('层级1,默认zIndex=0,底层。')
.width(200)
.height(200)
.backgroundColor('#007DFF')
.zIndex(0)
Text('层级2,zIndex=1,上层。')
.width(100)
.height(100)
.backgroundColor('#FF6B00')
.zIndex(1)
}
四、常用基础组件
1. 文本组件 Text
-
用于界面文本内容展示,是最基础的内容组件。
-
支持丰富的文本样式与展示规则配置。
基础语法
Text('文本内容')
核心样式配置
Text('鸿蒙ArkUI开发')
.fontSize(20) // 字体大小 单位fp
.fontWeight(FontWeight.Bold) // 字体粗细 支持枚举、100-900数值
// 默认400(Normal) 700等同于Bold
.fontColor(Color.Blue) // 字体颜色 支持枚举、16进制色值
// 16进制色值属于字符串 要用引号包裹
.lineHeight(30) // 文本行高 控制垂直间距
.textAlign(TextAlign.Center) // 文本水平对齐方式
文本溢出处理
-
超长文本的展示控制
-
textOverflow必须配合maxLines和固定宽度width使用,三者缺一不可,否则不生效。
Text('这是一段超长的文本内容,用于测试文本溢出省略的效果,超出指定行数后会自动显示省略号')
.width(200) // 必须约束宽度 否则文本会无限撑开
.maxLines(2) // 限制最大显示行数
.textOverflow({ overflow: TextOverflow.Ellipsis }) // 溢出显示省略号
溢出模式可选值:
-
TextOverflow.Ellipsis:溢出文本显示省略号 -
TextOverflow.Clip:溢出文本直接裁切(无省略号) -
TextOverflow.Marquee:文本单行滚动跑马灯效果(maxLines设置无效)
2. 图片组件 Image
-
用于界面图片展示
-
支持本地图片、网络图片、SVG图标
-
可灵活控制缩放与展示效果。
-
SVG图标:svg图标任意放大缩小不失真、可以修改颜色
-
HarmonyOS官方图标库: developer.huawei.com/consumer/cn…
基础语法
Image(图片数据源)
网络图片加载
-
直接传入图片网络地址字符串
-
必须先申请网络权限,否则无法加载。
Image('https://example.com/image.jpg')
.width(200)
.height(200)
.objectFit(ImageFit.Cover) // 图片缩放模式
- 网络权限配置步骤
(1)打开项目路径 main/module.json5 文件
(2)在 module 节点下添加 requestPermissions 配置:
{
"requestPermissions": [
{
"name": "ohos.permission.INTERNET",
"reason": "$string:internet_permission_reason",
"usedScene": {
"abilities": ["EntryAbility"],
"when": "inuse"
}
}
]
}
(3)在 main/resources/base/element/string.json 中添加权限说明:
{
"name": "internet_permission_reason",
"value": "用于加载网络图片资源"
}
本地图片/SVG图标引用
(1)本地图片或SVG图标需存放至项目固定路径 main/resources/base/media 目录下
(2)文件名禁止使用中文、空格、特殊符号(无需写文件后缀名)
(3)通过 $r 资源引用语法调用,SVG图标可通过 fillColor 修改颜色。
// 本地图片示例:media目录下有一张logo.png
Image($r('app.media.logo'))
.width(150)
.height(50)
// SVG图标示例:media目录下有一张ic_back.svg
Image($r('app.media.ic_back'))
.width(24)
.height(24)
.fillColor('#333333') // 修改SVG图标颜色
// svg图标文件的命名一般为ic_xxx
图片缩放模式 objectFit
| 枚举值 | 核心效果 | 适用场景 |
|---|---|---|
ImageFit.Cover | 等比例缩放至铺满容器 不变形、裁切多余部分 | 封面图、背景图等 需要填满容器的场景 |
ImageFit.Contain | 等比例缩放至完整展示 不变形、容器可能留白 | 商品图、logo图等 需要完整展示内容的场景 |
3. 输入框组件 TextInput
-
用于接收用户输入的文本内容
-
常用于登录、注册、表单等场景
-
支持多种输入类型与内容实时监听
基础语法
TextInput(参数对象)
.属性方法()
.事件回调()
核心用法示例
// 用户名输入框(明文)
TextInput({
placeholder: '请输入用户名' // 无输入时的占位提示文本
})
.type(InputType.Normal) // 输入框类型 普通明文输入
.width('100%')
.height(45)
// 密码输入框(密文)
TextInput({
placeholder: '请输入密码'
})
.type(InputType.Password) // 密码类型 输入内容自动隐藏
.width('100%')
.height(45)
常用输入类型
| 类型枚举 | 适用场景 |
|---|---|
InputType.Normal | 普通文本输入 明文显示 无特殊限制 |
InputType.Password | 密码输入 密文隐藏内容 |
InputType.Email | 邮箱地址输入 |
InputType.Number | 纯数字输入 |
InputType.NumberDecimal | 带小数点的数字输入 |
InputType.PhoneNumber | 手机号输入 |
InputType.URL | 网址链接输入 |
输入内容实时获取
-
通过
onChange事件实时监听用户输入 -
搭配
@State状态变量存储输入内容,实现数据双向绑定。
@State 是响应式状态装饰器,变量值变化时UI会自动刷新。
onChange 输入变化回调,用户输入时实时触发,将最新输入值赋值给对应的 @State 变量,实现数据→状态→UI的同步。
@Entry
@Component
struct InputDemo {
// 声明状态变量 存储输入内容
@State userName: string = ''
@State password: string = ''
build() {
Column({ space: 20 }) {
// 用户名输入框 绑定状态
TextInput({ placeholder: '请输入用户名' })
.type(InputType.Normal)
.width('100%')
.height(45)
.onChange((value: string) => {
this.userName = value // 实时赋值给状态变量
})
// 密码输入框 绑定状态
TextInput({ placeholder: '请输入密码' })
.type(InputType.Password)
.width('100%')
.height(45)
.onChange((value: string) => {
this.password = value
})
}
.padding(20)
.width('100%')
.height('100%')
}
}
4. 按钮组件 Button
-
用于响应用户点击操作
-
是界面交互的核心组件
-
支持文本按钮、自定义子组件按钮等多种形式
基础语法
// 文本按钮
Button('按钮显示文本')
.属性方法()
.onClick(() => {
// 点击按钮执行的业务逻辑
})
// 自定义子组件按钮
Button() {
// 自定义按钮内的UI内容
Row({ space: 8 }) {
Image($r('app.media.ic_login'))
.width(20)
.height(20)
Text('登录')
}
}
.onClick(() => {
// 点击按钮执行的业务逻辑
})
常用样式示例
Button('登录')
.width('100%')
.height(50)
.fontSize(18)
.fontWeight(FontWeight.Medium)
.backgroundColor('#007DFF')
.fontColor(Color.White)
.borderRadius(25)
.onClick(() => {
// 点击登录按钮,执行登录逻辑
console.log('点击了登录按钮')
})
五、布局容器组件
容器组件是布局的核心,用于控制子组件的排列方式、尺寸约束,是搭建页面骨架的核心能力。
1. 线性布局:Column列布局
-
垂直方向排列子组件,是页面最常用的根容器。
-
主轴为垂直方向,交叉轴为水平方向
// space参数:控制子组件之间的垂直间距
Column({ space: 20 }) {
Text('文本1')
Text('文本2')
Text('文本3')
}
.justifyContent(FlexAlign.Center) // 主轴对齐:垂直方向子组件排列
.alignItems(HorizontalAlign.Start) // 交叉轴对齐:水平方向子组件排列
.width('100%')
.height('100%')
| 配置项 | 作用 | 常用枚举值 |
|---|---|---|
space 参数 | 子组件之间的垂直间距 | 单位vp |
justifyContent 属性 | 主轴(垂直)对齐方式 | FlexAlign.Start 顶部对齐(默认)FlexAlign.Center 垂直居中FlexAlign.End 底部对齐FlexAlign.SpaceBetween 上下元素贴边对齐FlexAlign.SpaceAround 所有元素上下两侧均分间距FlexAlign.SpaceEvenly 所有间距完全均分 |
alignItems 属性 | 交叉轴(水平)对齐方式 | HorizontalAlign.Start 居左对齐HorizontalAlign.Center 水平居中(默认)HorizontalAlign.End 居右对齐 |
2. 线性布局:Row行布局
-
水平方向排列子组件,常用于横向排列的标签栏、按钮组、信息行等场景。
-
主轴为水平方向,交叉轴为垂直方向
// space参数:控制子组件之间的水平间距
Row({ space: 10 }) {
Text('首页')
Text('分类')
Text('我的')
}
.justifyContent(FlexAlign.SpaceEvenly) // 主轴对齐:水平方向子组件排列
.alignItems(VerticalAlign.Center) // 交叉轴对齐:垂直方向子组件排列
.width('100%')
.height(50)
| 配置项 | 作用 | 常用枚举值 |
|---|---|---|
space 参数 | 子组件之间的水平间距 | 单位vp |
justifyContent 属性 | 主轴(水平)对齐方式 | FlexAlign.Start 居左对齐(默认)FlexAlign.Center 水平居中FlexAlign.End 居右对齐FlexAlign.SpaceBetween 左右元素贴边对齐FlexAlign.SpaceAround 所有元素左右两侧均分间距FlexAlign.SpaceEvenly 所有间距完全均分 |
alignItems 属性 | 交叉轴(垂直)对齐方式 | VerticalAlign.Top 居上对齐VerticalAlign.Center 垂直居中(默认)VerticalAlign.Bottom 居下对齐 |
3. 自适应权重 layoutWeight
-
用于实现子组件的自适应伸缩
-
设置该属性的子组件,会按照权重分配主轴的剩余空间,是适配不同屏幕宽度的核心能力。
核心规则
-
数字参数为权重份数,剩余空间会按权重比例分配给对应子组件。
-
固定尺寸的子组件不设置layoutWeight,自适应的子组件设置对应权重。
-
仅在父容器的主轴方向生效(Column垂直方向生效,Row水平方向生效)。
Row({ space: 10 }) {
// 固定宽度组件
Image($r('app.media.ic_avatar'))
.width(40)
.height(40)
// 自适应宽度组件 占据剩余所有空间
Text('用户昵称')
.layoutWeight(1)
.fontSize(16)
// 固定宽度组件
Text('关注')
.width(60)
.height(30)
.textAlign(TextAlign.Center)
.backgroundColor('#007DFF')
.fontColor(Color.White)
.borderRadius(15)
}
.width('100%')
.padding(20)
4. 弹性布局 Flex
-
弹性布局是更灵活的线性布局
-
核心特性是支持子元素换行、自动压缩
-
适合不规则的多元素排列、标签流等场景
-
单行单列布局建议优先使用线性布局,线性布局的性能优化更高。
-
线性布局Column和Row默认情况下是不支持换行的
// 语法
Flex(参数对象){
子组件1
子组件2
子组件3
......
子组件n
}
-
弹性布局Flex又被称为伸缩布局,当子元素的总和溢出父元素时,默认进行压缩显示。
-
Flex默认主轴水平往右、交叉轴垂直往下(与Row相似)
-
主轴方向 direction :
FlexDirection.Row、FlexDirection.Column -
主轴对齐方式 justifyContent :
FlexAlign.枚举 -
交叉轴对齐方式 alignItems :
ItemAlign.枚举 -
Flex布局换行 wrap :
FlexWrap.Wrap换行 、FlexWrap.NoWrap不换行
// 不规则的布局方式只能用FlexWrap来解决
Flex({
wrap : FlexWrap.Wrap
})
// 换行标签流示例
Flex({
wrap: FlexWrap.Wrap, // 开启换行 (默认为NoWrap不换行)
direction: FlexDirection.Row, // 主轴方向 (默认Row水平方向)
justifyContent: FlexAlign.Start, // 主轴对齐
alignItems: ItemAlign.Center, // 交叉轴对齐
space: 10 // 子组件间距
}) {
Text('鸿蒙开发')
Text('ArkTS')
Text('声明式UI')
Text('组件化开发')
Text('HarmonyOS NEXT')
Text('移动端开发')
}
.padding(20)
.width('100%')
5. 层叠布局 Stack
-
层叠布局用于实现子组件的层叠效果
-
子组件默认按照代码顺序,后写的覆盖先写的。
-
支持统一设置对齐方式,比绝对定位更简洁,编码效率更高。
// 语法
Stack({
alignContent : Alignment.Center
}){
Item1()
Item2()
Item3()
......
}
// 默认居中Alignment.Center
// ({ alignContent : Alignment.Center }可不写)
// TopStart左上 、Top中上 、TopEnd右上
// Start左 、Center中 、End右
// BottomStart左下 、Bottom中下 、BottomEnd右下
// 图片+角标示例
Stack({
alignContent: Alignment.TopEnd // 子组件默认对齐方式,默认Center居中
}) {
// 底层图片
Image($r('app.media.goods_img'))
.width(120)
.height(120)
.borderRadius(8)
.objectFit(ImageFit.Cover)
// 上层热销角标
Text('热销')
.fontSize(12)
.fontColor(Color.White)
.backgroundColor('#FF4D4F')
.padding({ left: 8, right: 8, top: 2, bottom: 2 })
.borderRadius({ topRight: 8, bottomLeft: 8 })
}