本文献给:

已完成环境搭建、能成功运行第一个鸿蒙项目的开发者。本文将系统讲解 HarmonyOS 中常用的基础组件和布局容器,并带你实现沉浸式效果,帮助你搭建出美观实用的应用界面。


你将学到:

  1. Text、Button、Image 等基础组件的常用属性与事件
  2. TextInput、Progress、List 等交互组件的基本用法
  3. Column、Row、Flex 线性与弹性布局
  4. RelativeContainer 锚点相对布局
  5. Stack 层叠布局与 Grid 网格布局
  6. 沉浸式效果(状态栏/导航栏透明)的实现方法



一、基础组件(上)—— Text、Button、Image

1.1 Text 文本组件

Text 是用于显示文本的基础组件,支持多种样式和事件。

@Entry
@Component
struct TextDemo {
  build() {
    Column() {
      Text('Hello HarmonyOS')
        .fontSize(24)           // 字号
        .fontColor(Color.Blue)  // 字体颜色
        .fontWeight(FontWeight.Bold) // 粗细
        .textAlign(TextAlign.Center) // 对齐方式
        .maxLines(2)            // 最大行数
        .textOverflow({ overflow: TextOverflow.Ellipsis }) // 溢出省略号
        .onClick(() => {         // 点击事件
          console.log('Text clicked');
        })
    }
    .width('100%')
    .padding(20)
  }
}

常用属性速览:

属性 说明
.fontSize(size) 字号,单位 vp
.fontColor(color) 字体颜色
.fontWeight(weight) 粗细,如 FontWeight.Bold
.textAlign(align) 水平对齐
.maxLines(n) 最大行数
.textOverflow({ overflow }) 溢出处理,可选 Clip / Ellipsis
.onClick(callback) 点击事件

1.2 Button 按钮组件

Button 是最常用的交互组件,支持多种样式和表单。

Button('点击我', { type: ButtonType.Capsule, stateEffect: true })
  .fontSize(18)
  .width('60%')
  .height(40)
  .backgroundColor(Color.Green)
  .borderRadius(20)
  .onClick(() => {
    // 处理点击逻辑
  })
  • type:按钮类型,Capsule(胶囊)、Normal(默认)、Circle(圆形)。
  • stateEffect:是否开启点击态效果(按下时变暗)。
  • 支持所有通用样式(宽高、背景、圆角等)。

1.3 Image 图片组件

Image 用于显示本地或网络图片。

// 本地资源(放在 resources/base/media 目录下)
Image($r('app.media.icon'))
  .width(100)
  .height(100)
  .objectFit(ImageFit.Cover)   // 图片填充方式

// 网络图片
Image('https://example.com/photo.jpg')
  .width(200)
  .height(200)
  .borderRadius(10)

常用属性:

  • objectFitCover(裁剪填充)、Contain(完整显示)、Fill(拉伸变形)。
  • 网络图片需要声明网络权限(在 module.json5 中添加 ohos.permission.INTERNET)。

二、基础组件(下)—— TextInput、Progress、List

2.1 TextInput 输入框

用于接收用户文本输入。

@State inputValue: string = '';

TextInput({ placeholder: '请输入用户名', text: this.inputValue })
  .width('80%')
  .height(40)
  .backgroundColor(Color.White)
  .borderRadius(8)
  .type(InputType.Normal)     // 输入类型:Normal / Password / Email 等
  .onChange((value: string) => {
    this.inputValue = value;  // 实时更新状态
  })
  • placeholder:占位提示文字。
  • typeNormal / Password / Email / Number 等。
  • .onChange 用于监听输入变化,通常配合 @State 实现双向绑定。

2.2 Progress 进度条

用于显示操作进度或加载状态。

Progress({ value: 60, total: 100, type: ProgressType.Linear })
  .width('80%')
  .height(20)
  .color(Color.Blue)
  • value / total:当前值与总值。
  • typeLinear(条形)、Ring(环形)、ScaleRing(带刻度环形)、Eclipse(月食形)、Capsule(胶囊形)。

2.3 List 列表组件

用于展示可滚动的列表数据。

@State items: string[] = ['项目 A', '项目 B', '项目 C'];

List() {
  ForEach(this.items, (item: string, index: number) => {
    ListItem() {
      Text(item)
        .fontSize(18)
        .padding(12)
    }
    .border({ width: { bottom: 1 }, color: '#eee' })
  })
}
.width('100%')
.height('60%')
  • 必须与 ListItem 配合使用。
  • ForEach 用于循环渲染列表项,需要提供唯一 key(此示例索引自动生成)。
  • 支持设置分割线、滚动条、编辑模式等。

三、线性布局 —— Column 与 Row

线性布局是最基础的布局方式,Column 表示垂直排列,Row 表示水平排列。

3.1 Column 垂直布局

Column({ space: 10 }) {  // space 设置子组件间距
  Text('第一行')
  Text('第二行')
  Button('按钮')
}
.width('100%')
.height(200)
.backgroundColor('#f5f5f5')
.justifyContent(FlexAlign.Center)  // 主轴(垂直)对齐
.alignItems(HorizontalAlign.Start) // 交叉轴(水平)对齐
  • justifyContent 控制主轴对齐(Start / Center / End / SpaceBetween 等)。
  • alignItems 控制交叉轴对齐(Start / Center / End)。

3.2 Row 水平布局

Row({ space: 8 }) {
  Image($r('app.media.icon')).width(40).height(40)
  Text('标题').fontSize(18)
  Blank()  // 空白占位,推动后面的元素靠右
  Button('操作').width(60).height(30)
}
.width('90%')
.height(60)
.padding(10)
  • Blank() 组件可占据剩余空间,常用于两端对齐。
  • 支持 layoutWeight 属性,设置子组件在主轴上的权重分配(类似 Flex 的 flex-grow)。

四、弹性布局 —— Flex

Flex 提供了比 Column/Row 更灵活的弹性盒子模型,当效果用 Column/Row 难以实现时,可以使用 Flex。

Flex({
  direction: FlexDirection.Row,       // 主轴方向
  wrap: FlexWrap.Wrap,                // 自动换行
  justifyContent: FlexAlign.SpaceAround,
  alignItems: ItemAlign.Center
}) {
  Text('A').width(80).height(60).backgroundColor(Color.Red)
  Text('B').width(80).height(60).backgroundColor(Color.Green)
  Text('C').width(80).height(60).backgroundColor(Color.Blue)
}
.width('100%')
.height(150)
.backgroundColor('#f0f0f0')

与 Column/Row 的区别:

  • Column/Row 是 Flex 的特定封装(方向固定)。
  • Flex 可直接设置 direction,支持 ColumnRowColumnReverseRowReverse
  • Flex 的 wrap 属性能实现自动换行,更适合弹性伸缩场景。

五、相对布局 —— RelativeContainer

RelativeContainer 允许子组件相对于父容器或其他子组件进行定位,通过锚点实现复杂界面。

5.1 基本用法

RelativeContainer() {
  Text('左上角')
    .alignRules({
      top: { anchor: '__container__', align: VerticalAlign.Top },
      left: { anchor: '__container__', align: HorizontalAlign.Start }
    })
    .id('topLeftText')

  Button('右下角')
    .alignRules({
      bottom: { anchor: '__container__', align: VerticalAlign.Bottom },
      right: { anchor: '__container__', align: HorizontalAlign.End }
    })
    .id('bottomRightBtn')
}
.width('100%')
.height(300)
.backgroundColor(Color.White)
  • '__container__' 代表父容器。
  • 通过 topbottomleftrightcentermiddle 等规则设定对齐目标。
  • 每个子组件必须有唯一的 id,用于其他组件参考。

5.2 相对于其他子组件定位

RelativeContainer() {
  Image($r('app.media.avatar'))
    .width(60)
    .height(60)
    .id('avatar')
    .alignRules({
      center: { anchor: '__container__', align: VerticalAlign.Center },
      middle: { anchor: '__container__', align: HorizontalAlign.Center }
    })

  Text('用户名')
    .id('username')
    .alignRules({
      top: { anchor: 'avatar', align: VerticalAlign.Bottom }, // 在头像下方
      middle: { anchor: 'avatar', align: HorizontalAlign.Center }
    })
    .margin({ top: 10 })
}
.width('100%')
.height(200)

这种相对定位方式避免了复杂的嵌套布局,代码更扁平、易维护。


六、其他常用容器 —— Stack 与 Grid

6.1 Stack 层叠布局

Stack 将子组件按添加顺序层叠放置,后添加的组件显示在上层。常用于悬浮按钮、文字覆盖图片等场景。

Stack({ alignContent: Alignment.BottomEnd }) {
  Image($r('app.media.banner'))
    .width('100%')
    .height(200)

  Button('查看详情')
    .margin(16)
    .backgroundColor(Color.Orange)
}
.width('90%')
.height(200)
.borderRadius(10)
  • alignContent 设置所有子组件的默认对齐方式,可被单个子组件覆盖。
  • 使用 positionoffset 可实现更精细的定位。

6.2 Grid 网格布局

Grid 用于创建多行多列的布局,适合相册、商品列表等。

@State items: string[] = ['1', '2', '3', '4', '5', '6'];

Grid() {
  ForEach(this.items, (item: string) => {
    GridItem() {
      Text(item)
        .width('100%')
        .height(100)
        .textAlign(TextAlign.Center)
        .backgroundColor(Color.Orange)
        .borderRadius(8)
    }
  })
}
.columnsTemplate('1fr 1fr 1fr') // 三列等分
.rowsGap(10)
.columnsGap(10)
.width('90%')
.height(300)
  • columnsTemplate:定义列宽模板,'1fr 1fr' 表示两列等分。
  • rowsTemplate:定义行高模板。
  • 支持 GridItem 的合并单元格(rowStart/rowEndcolumnStart/columnEnd)。

七、沉浸式效果实现

沉浸式效果让应用界面延伸到状态栏和导航栏区域,提升视觉体验。

7.1 核心概念

  • 窗口安全区:为避免被系统栏遮挡,系统默认会为应用内容留出安全区域。
  • 实现沉浸式需要让内容延伸到安全区,并处理可能的遮挡问题。

7.2 实现步骤

第 1 步:设置窗口全屏布局

module.json5 中对 Ability 进行配置:

{
  "abilities": [{
    "name": "EntryAbility",
    "window": {
      "fullScreen": true
    }
  }]
}

或者在页面中动态设置:

import window from '@ohos.window';

onPageShow() {
  window.getLastWindow(getContext()).then((win) => {
    win.setWindowLayoutFullScreen(true);
  });
}

第 2 步:使用 expandSafeArea 属性

在布局根组件上使用 .expandSafeArea,让内容延伸到安全区。

Column()
  .expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])
  .width('100%')
  .height('100%')
  .linearGradient({
    angle: 180,
    colors: [[0x1E90FF, 0.0], [0x87CEEB, 1.0]]
  })
  • SafeAreaType.SYSTEM:指状态栏和导航栏区域。
  • SafeAreaEdge.TOP / BOTTOM:指定在哪些边缘扩展。

第 3 步:处理重叠内容

内容扩展后,可能会和状态栏图标重叠。可以为顶部标题增加 padding 或使用 margin 避开。

Column() {
  Text('首页标题')
    .fontSize(20)
    .fontColor(Color.White)
    .margin({ top: 30 })  // 向下偏移,避免与状态栏重叠
  // 其他内容...
}
.width('100%')
.height('100%')
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP])

通过上述配置,即可实现背景延伸到状态栏的沉浸式效果。


八、常见错误与注意事项

8.1 布局未填满父容器

Column/Row 默认高度/宽度根据内容自适应,若想占满父容器,需显式设置 .width('100%').height('100%')

8.2 组件 id 重复导致 RelativeContainer 报错

每个子组件 id 必须唯一,否则运行时报错。使用有意义的 id 并检查重复。

8.3 Grid 未指定列模板导致布局异常

Grid 必须设置 columnsTemplate,否则可能只显示一列。通常使用 '1fr 1fr' 等 fr 单位。

8.4 沉浸式效果但部分手机仍有黑边

  • 确认已设置 fullScreen: true 或调用 setWindowLayoutFullScreen
  • 检查是否同时设置了 expandSafeArea,只设全屏而不扩展安全区无法让内容绘制到状态栏下方。
  • 某些系统组件(如 TitleBar)可能自带安全区适配,需自行处理。

8.5 List 性能问题

长列表建议使用 LazyForEach 替代 ForEach,实现懒加载,提升性能。


九、小结

组件 / 布局 关键点
Text、Button、Image 基础显示与交互组件,常用样式属性
TextInput、Progress、List 高级交互与数据展示组件
Column / Row 线性布局,主轴与交叉轴对齐
Flex 弹性布局,支持换行和反转
RelativeContainer 锚点相对定位,减少嵌套
Stack 层叠布局,适合悬浮效果
Grid 网格布局,适合多列排列
沉浸式效果 通过 fullScreenexpandSafeArea 实现背景延伸至状态栏



觉得文章有帮助?别忘了:

👍 点赞 👍 – 给我一点鼓励
⭐ 收藏 ⭐ – 方便以后查看
🔔 关注 🔔 – 获取更新通知



标签: #HarmonyOS #ArkUI #布局 #沉浸式效果 #基础组件 #学习笔记 #鸿蒙开发

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐