HarmonyOS鸿蒙开发 | ArkUI组件与布局

0 阅读9分钟

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
标准界面开发流程

遵循「 先排版 → 再填内容 → 最后美化 」的核心思路:

  1. 拆分界面结构,用容器组件完成整体行列排版,确定页面骨架。
  2. 在对应容器中放入基础组件,填充文本、图片、按钮等界面内容。
  3. 通过属性方法为组件设置样式、交互,完成界面美化与功能开发。



三、组件通用属性

通用属性可用于所有组件,用于约束组件尺寸、美化外观、控制位置,是界面开发的基础能力。

核心尺寸单位规范

鸿蒙开发中需严格区分3种核心单位(避免多设备适配异常):

单位全称适用场景核心特性
vpVirtual Pixel组件宽高、内边距、外边距、定位等布局尺寸虚拟像素
会根据设备屏幕密度自动适配
保证不同设备视觉效果一致
布局首选单位
fpFont Pixel字体大小跟随系统字体大小缩放
兼顾视觉效果与无障碍适配
字体首选单位
pxPixel仅特殊场景使用设备物理像素点
不同设备分辨率差异大
不推荐直接用于布局
可通过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 居右对齐

主轴对齐.jpg

Column.jpg

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 居下对齐

Row.jpg

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)

自适应伸缩.jpg


4. 弹性布局 Flex
  • 弹性布局是更灵活的线性布局

  • 核心特性是支持子元素换行、自动压缩

  • 适合不规则的多元素排列、标签流等场景

  • 单行单列布局建议优先使用线性布局,线性布局的性能优化更高。

  • 线性布局Column和Row默认情况下是不支持换行的

// 语法
Flex(参数对象){
   子组件1
   子组件2
   子组件3
   ......
   子组件n
}
  • 弹性布局Flex又被称为伸缩布局,当子元素的总和溢出父元素时,默认进行压缩显示。

  • Flex默认主轴水平往右、交叉轴垂直往下(与Row相似)

  • 主轴方向 direction : FlexDirection.RowFlexDirection.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%')

弹性布局.png

5. 层叠布局 Stack
  • 层叠布局用于实现子组件的层叠效果

  • 子组件默认按照代码顺序,后写的覆盖先写的。

  • 支持统一设置对齐方式,比绝对定位更简洁,编码效率更高。

// 语法
Stack({
  alignContent : Alignment.Center
}){
  Item1()
  Item2()
  Item3()
  ......
}
// 默认居中Alignment.Center
// ({ alignContent : Alignment.Center }可不写)
// TopStart左上 、Top中上 、TopEnd右上
// Start左 、Center中 、End右
// BottomStart左下 、Bottom中下 、BottomEnd右下

层叠布局.jpg

// 图片+角标示例
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 })
}