鸿蒙原生 ArkTS 布局精讲:Grid 组件实现九宫格布局(HarmonyOS NEXT API 24)


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一、引言

1.1 为什么是九宫格?

九宫格(3×3 Grid)是移动端 UI 中最经典、最基础的网格布局形态。从手机桌面图标排列、相机滤镜选择、密码手势解锁,到功能入口矩阵("我的"页面中的九宫格功能模块),九宫格无处不在。它是每一个鸿蒙开发者必须掌握的基础布局能力。

在 HarmonyOS NEXT 中,实现九宫格最优雅的方式就是使用 ArkUI 提供的 Grid 容器组件。本文将以一个完整的九宫格示例项目为主线,从零开始讲解 Grid 组件的核心 API、布局原理、样式定制和工程最佳实践,帮助读者彻底掌握鸿蒙原生网格布局。

1.2 目标读者

本文面向以下读者:

  • 刚接触 HarmonyOS NEXT 开发、想系统学习 ArkTS 布局的初学者
  • 已有前端或 Android/iOS 经验、正在迁移到鸿蒙生态的开发者
  • 希望深入理解 Grid 组件 API 细节、追求高性能布局的中级开发者

1.3 技术栈一览

技术 版本 / 说明
HarmonyOS NEXT API 24(最新稳定版)
声明式开发语言 ArkTS(基于 TypeScript)
UI 框架 ArkUI 全局组件(无需 import)
构建工具 hvigor
开发 IDE DevEco Studio NEXT

二、Grid 组件概述

2.1 什么是 Grid?

Grid(网格容器)是 ArkUI 提供的一种 二维布局容器,能够将子组件按行和列排列成规则的网格结构。与传统的线性布局(Column/Row)相比,Grid 天然支持横纵两个方向的排列控制,非常适合实现九宫格、相册缩略图、商品列表等需要规整排列的场景。

2.2 Grid 与 Flex / List 的对比

为了帮助读者理解 Grid 的定位,下面将它与鸿蒙中其他常见布局容器进行对比:

特性 Grid Column / Row Flex List
布局维度 二维(行+列) 一维(单方向) 一维(单方向) 一维(滚动列表)
行列控制 columnsTemplate + rowsTemplate
自动换行 支持 不支持 支持(wrap) 不支持
滚动 可启用 不原生支持 不原生支持 专为滚动优化
子组件间距 columnsGap + rowsGap space 参数 gap space
适用场景 网格 / 表格 / 九宫格 线性排列 流式布局 长列表

总结:如果你的 UI 是"方方正正"的格子形态,Grid 是第一选择,而非 Column 多层嵌套或 Flex 的折行方案。

2.3 Grid 在 API 24 中的新特性

HarmonyOS NEXT API 24 对 Grid 组件做了进一步优化和增强,主要包括:

  1. 更高效的懒加载机制:当 Grid 包含大量子项(如 1000+ GridItem)时,API 24 优化了不可见项的回收策略,减少了 GPU 渲染压力。
  2. 跨端适配增强:Grid 的 columnsTemplaterowsTemplate 现在支持更灵活的单位组合,包括 %pxvpfr 的混合使用。
  3. 新的子组件对齐能力GridItem 新增了 alignSelf 属性,允许单个格子覆盖容器的默认对齐方式。
  4. 动画支持:Grid 的 columnsGaprowsGap 现在可以参与动画过渡,实现间距动态变化的流畅效果。
  5. 无障碍访问增强:Grid 和 GridItem 自动获得了无障碍焦点遍历顺序,无需开发者手动设置 tabIndex

本文的示例将基于 API 24 编写,充分利用这些新特性。


三、项目搭建与工程结构

3.1 创建项目

使用 DevEco Studio NEXT 创建一个新的 HarmonyOS 工程:

  1. 打开 DevEco Studio,点击 Create Project
  2. 选择 Empty Ability 模板
  3. 配置项目名称(如 app014)、包名、存储路径
  4. Compatible SDK 中选择 API 24
  5. 点击 Finish 完成创建

3.2 项目结构说明

创建完成后,项目的主要结构如下:

app014/
├── entry/
│   ├── src/main/
│   │   ├── ets/
│   │   │   ├── entryability/        # Ability 生命周期
│   │   │   │   └── EntryAbility.ets
│   │   │   └── pages/               # 页面目录
│   │   │       └── Index.ets         # 主页面(九宫格)
│   │   ├── module.json5             # 模块配置
│   │   └── resources/               # 资源文件
│   ├── build-profile.json5          # 模块构建配置
│   └── oh-package.json5             # 依赖管理
├── build-profile.json5              # 工程构建配置
├── oh-package.json5                 # 工程依赖
└── hvigor/
    └── hvigor-config.json5          # hvigor 配置

我们所有的 UI 代码都集中在 entry/src/main/ets/pages/Index.ets 中,这也是本文重点讲解的文件。


四、完整代码实现

4.1 数据模型定义

首先,我们需要定义九宫格中每个格子的数据结构。在 ArkTS 中,使用 interface 来声明类型:

/**
 * 九宫格每一项的数据模型
 * id    : 唯一标识(1~9)
 * label : 格子里显示的中文数字(一~九)
 * color : 格子的背景色
 */
interface GridCell {
  id: number;
  label: string;
  color: ResourceColor;
}
  • id:数字编号,同时用作 ForEach 的键值(key),保证列表 diff 算法高效运行。
  • label:显示在格子中的文字,这里使用中文数字 “一” 到 “九”,增加文化特色。
  • color:背景色,类型为 ResourceColor(ArkTS 中表示颜色值的类型),可以是十六进制字符串、RGB/RGBA 或 Resource 引用。

4.2 页面结构与 @State 数据源

使用 @Entry@Component 装饰器声明页面组件:

@Entry
@Component
struct Index {
  @State cells: GridCell[] = [
    { id: 1,  label: '一',  color: '#FF6B81'  },
    { id: 2,  label: '二',  color: '#5B8FF9'  },
    { id: 3,  label: '三',  color: '#5AD8A6'  },
    { id: 4,  label: '四',  color: '#F6BD16'  },
    { id: 5,  label: '五',  color: '#7262FD'  },
    { id: 6,  label: '六',  color: '#FF9D4D'  },
    { id: 7,  label: '七',  color: '#B37FEB'  },
    { id: 8,  label: '八',  color: '#3DC27F'  },
    { id: 9,  label: '九',  color: '#F56C6C'  },
  ];
  // ... build() 方法
}

关键知识点

  • @Entry:标记该组件为页面的入口组件,系统会自动为它创建页面路由。
  • @Component:声明这是一个可复用的自定义组件。
  • @State:装饰的状态变量。当 cells 数组发生变化时,UI 会自动重新渲染。
  • 9 种对比鲜明的颜色:红、蓝、绿、黄、紫、橙、浅紫、翠绿、朱红,每种颜色都与对应的中文数字配合,视觉层次分明。

4.3 build() 方法:搭建三层结构

在 ArkTS 中,UI 是由 build() 方法中的声明式代码"描述"出来的。我们的页面采用从上到下的三层结构:

Column(全屏渐变背景)
 ├── Text 区域(标题 + 副标题)
 ├── Grid 区域(核心九宫格,3×3)
 └── Row 区域(底部提示条)
4.3.1 最外层:Column + 渐变背景
build() {
  Column() {
    // ... 子组件
  }
  .width('100%')
  .height('100%')
  .linearGradient({
    direction: GradientDirection.Bottom,
    colors: [['#F0F4F8', 0.0], ['#E8ECF2', 1.0]]
  })
  .alignItems(HorizontalAlign.Center)
}
  • width('100%')height('100%'):Column 铺满整个屏幕。
  • linearGradient:顶部浅灰蓝 #F0F4F8 渐变到底部 #E8ECF2,比纯白色背景更柔和、更有质感。
  • alignItems(HorizontalAlign.Center):所有子组件水平居中。
4.3.2 标题区域
Text('✦ 九宫格布局(3×3 Grid)')
  .fontSize(22)
  .fontWeight(FontWeight.Bold)
  .fontColor('#2C3E50')
  .margin({ top: 32, bottom: 8 })
  .textAlign(TextAlign.Center)

Text('Grid + columnsTemplate/rowsTemplate')
  .fontSize(14)
  .fontColor('#95A5A6')
  .margin({ bottom: 24 })
  • 主标题使用 22fp 加粗字体,深灰蓝色 #2C3E50
  • 副标题 14fp,浅灰色 #95A5A6,作为技术词汇的补充说明。
4.3.3 核心:Grid 九宫格

这是整个页面的核心,也是本文重点讲解的部分:

Grid() {
  ForEach(this.cells, (item: GridCell) => {
    GridItem() {
      Column() {
        Text(item.id.toString())
          .fontSize(28)
          .fontWeight(FontWeight.Bold)
          .fontColor('#FFFFFF')

        Text(item.label)
          .fontSize(16)
          .fontColor('rgba(255, 255, 255, 0.85)')
          .margin({ top: 6 })
      }
      .width('100%')
      .height('100%')
      .justifyContent(FlexAlign.Center)
      .alignItems(HorizontalAlign.Center)
    }
    .width('100%')
    .height('100%')
    .backgroundColor(item.color)
    .borderRadius(12)
    .onClick(() => {
      console.info(`[九宫格] 点击了第 ${item.id} 格:${item.label}`);
    })
  }, (item: GridCell) => item.id.toString())
}
.columnsTemplate('1fr 1fr 1fr')
.rowsTemplate('1fr 1fr 1fr')
.columnsGap(8)
.rowsGap(8)
.width('90%')
.height(360)
.borderRadius(16)
.padding(8)
.backgroundColor('#F5F7FA')
.shadow({
  radius: 12,
  color: 'rgba(0, 0, 0, 0.08)',
  offsetX: 0,
  offsetY: 4
})

这里集中呈现了 Grid 的绝大多数核心 API,下面逐一拆解。

4.3.4 底部提示区域
Row() {
  Text('💡 点击任意格子 → 查看 HiLog 日志')
    .fontSize(14)
    .fontColor('#7F8C8D')
}
.margin({ top: 24 })
.padding({ top: 12, bottom: 12, left: 20, right: 20 })
.backgroundColor('#ECF0F1')
.borderRadius(20)
  • 浅灰色胶囊形提示条,提示用户点击格子并通过 HiLog 查看日志输出。
  • 这种"交互 + 反馈"的设计能帮助学习者立刻验证代码是否按预期运行。

五、Grid 核心 API 深度解析

本章节对示例中使用的每一个 Grid API 进行详细解读,并结合源码说明其设计意图。

5.1 columnsTemplate:列模板

.columnsTemplate('1fr 1fr 1fr')

columnsTemplate 定义了 Grid 的列结构,是一个以空格分隔的字符串,每个 token 代表一列的宽度。

支持的宽度单位

单位 说明 示例
fr 比例单位(fraction),按比例分配剩余空间 '1fr 1fr 1fr' = 三等分
px 物理像素 '100px 1fr 1fr'
vp 虚拟像素(密度无关像素) '80vp 1fr 1fr'
% 父容器宽度的百分比 '30% 40% 30%'
auto 自适应内容宽度 'auto 1fr 1fr'

在九宫格中的含义'1fr 1fr 1fr' 表示 Grid 容器的宽度被三等分,每列占据 1 份可用空间。如果 Grid 宽度是屏幕宽度的 90%(通过 .width('90%') 设置),那么每列宽度就是 90% × 33.33% = 30% 的屏幕宽度。

实用技巧:如果要实现"中间宽、两侧窄"的布局,可以使用 columnsTemplate('1fr 2fr 1fr'),中间列会自动占据两倍的宽度。

5.2 rowsTemplate:行模板

.rowsTemplate('1fr 1fr 1fr')

columnsTemplate 对称,rowsTemplate 定义 Grid 的行高结构。'1fr 1fr 1fr' 表示 Grid 的高度被三等分,每行占据 1 份可用空间。

缺省行为:如果只设置 columnsTemplate 而不设置 rowsTemplate,Grid 会根据子项数量自动计算行数,并使用 auto 作为行高(即每行高度由子内容撑开)。对于九宫格这种需要严格等高的场景,必须同时设置 rowsTemplate

5.3 columnsGap 与 rowsGap:间距控制

.columnsGap(8)
.rowsGap(8)
  • columnsGap:列与列之间的间距,单位 vp。这里设为 8vp,在九宫格中表现为每个格子之间的水平间隔。
  • rowsGap:行与行之间的间距,单位 vp。设为 8vp,表现为垂直间隔。

等距还是非等距? 在九宫格中,通常 columnsGaprowsGap 设置相同的值,以保持视觉对称。但在某些特殊场景(如照片墙布局)中,可以让水平间距和垂直间距不同,创造独特的节奏感。

5.4 ForEach:高效循环渲染

ForEach(this.cells, (item: GridCell) => {
  // ... 渲染每个 GridItem
}, (item: GridCell) => item.id.toString())

ForEach 是 ArkTS 中用于列表渲染的内置组件,它接收三个参数:

  1. 数据源this.cells):要遍历的数组。
  2. 内容生成器(箭头函数):对每项数据,返回对应的 UI 组件树。
  3. 键值生成器(选填):为每项生成唯一的键(key),用于列表 diff 优化。

为什么要提供键值生成器?

当数据源发生变化时(如增删排序),ArkUI 框架需要知道哪些项是新插入的、哪些是删除的、哪些只是位置变化。如果没有键值,框架只能从头到尾重新渲染所有项,性能较差。有了稳定的键值(这里使用 item.id),框架可以精准定位变化,只更新受影响的部分。

注意:键值必须是稳定且唯一的。使用数组索引(index)作为键值是不推荐的,因为在数组增删后索引会变化,导致 diff 算法误判。

5.5 GridItem:网格中的最小单元

GridItem() {
  // 每个格子的内容
}
.width('100%')
.height('100%')
.backgroundColor(item.color)
.borderRadius(12)
.onClick(() => { ... })

GridItem 是 Grid 的直接子组件,代表网格中的一个单元格。它继承自 ArkUI 的基础组件,因此可以设置宽高、背景色、圆角、阴影、点击事件等。

重要设计原则

  • GridItem 的默认宽高受到 Grid 的行列模板约束,设置 width('100%')height('100%') 可以让它填满整个格子区域。
  • GridItem 内部只能有一个根组件(这里我们使用 Column),如果需要在格子中放置多个元素,必须嵌套在一个容器组件中。

5.6 shadow:阴影与立体感

.shadow({
  radius: 12,
  color: 'rgba(0, 0, 0, 0.08)',
  offsetX: 0,
  offsetY: 4
})

shadow 属性为 Grid 容器添加了外阴影效果,参数说明:

参数 含义
radius 12 阴影模糊半径,越大越模糊扩散
color rgba(0,0,0,0.08) 阴影颜色,8% 不透明度的黑色
offsetX 0 水平偏移(正数向右)
offsetY 4 垂直偏移(正数向下),4vp 的下沉阴影

视觉效果:Grid 容器仿佛悬浮在背景之上,增强了页面的层次感和精致度。注意阴影透明度要低(8%),否则会显得过于突兀。

5.7 borderRadius:圆角

// Grid 外容器圆角
.borderRadius(16)
// 每个 GridItem 格子圆角
.borderRadius(12)
  • Grid 容器使用 16vp 圆角,较大的圆角让整个九宫格区块更柔和。
  • 每个 GridItem 使用 12vp 圆角,略小于外容器,形成"内嵌"的视觉层次。
  • 圆角 + 背景色 + 阴影的组合是移动端"卡片设计"的三要素。

5.8 linearGradient:线性渐变

.linearGradient({
  direction: GradientDirection.Bottom,
  colors: [['#F0F4F8', 0.0], ['#E8ECF2', 1.0]]
})

linearGradient 为容器填充线性渐变背景:

  • direction:渐变方向。GradientDirection.Bottom 表示从上到下渐变。
  • colors:颜色断点数组。每个元素是 [颜色值, 位置] 的元组。['#F0F4F8', 0.0] 表示起点颜色,['#E8ECF2', 1.0] 表示终点颜色。

为什么使用渐变而不是纯色? 纯白背景在手机屏幕上显得单调乏味,微妙的灰蓝色渐变既不影响可读性,又能提升页面的视觉品质。


六、布局原理深入分析

6.1 九宫格的尺寸计算

以一张 360vp 宽、360vp 高的 Grid 容器为例,九宫格的尺寸计算如下:

已知:
  Grid 宽度  = 90% 屏幕宽度 ≈ 324vp(假设屏幕宽 360vp)
  Grid 高度  = 360vp
  columnsGap = 8vp(2 个间距)
  rowsGap    = 8vp(2 个间距)
  padding    = 8vp(左右各 8vp,上下各 8vp)

可用宽度 = 324 - 8×2 - 8×2 = 292vp
每列宽度 = 292 / 3 ≈ 97.3vp

可用高度 = 360 - 8×2 - 8×2 = 328vp
每行高度 = 328 / 3 ≈ 109.3vp

因此每个 GridItem 的实际尺寸约为 97vp × 109vp,这是一个接近正方形的矩形。如果希望 Grid 是完美的正方形,可以将 Grid 的宽高设置为相同的值,或者使用 aspectRatio 约束。

6.2 fr 单位的工作原理

fr(fraction,比例单位)是 Grid 布局中最灵活的单位。它的计算方式如下:

  1. 先减去所有固定宽度(px、vp、% 列)和间距(columnsGap)
  2. 将剩余可用空间按 fr 值的比例分配给各列

例如,columnsTemplate('100px 1fr 2fr') 的计算过程:

总宽度 = 324vp
固定列 = 100px(假设 ≈ 50vp)
间距   = 8vp × 2 = 16vp
剩余   = 324 - 50 - 16 = 258vp
比例   = 1fr : 2fr,共 3 份
列 1(1fr)= 258 / 3 × 1 = 86vp
列 2(2fr)= 258 / 3 × 2 = 172vp

正是因为 fr 的单位具有"分配剩余空间"的特性,'1fr 1fr 1fr' 才能完美实现三等分,无论容器宽度如何变化。

6.3 Grid 的自动换行机制

当 GridItem 的数量超过 columnsTemplate × rowsTemplate 的容量时,Grid 默认会自动增加行数来容纳额外的子项。例如,如果设置了 columnsTemplate('1fr 1fr 1fr')rowsTemplate('1fr 1fr 1fr'),但添加了 12 个 GridItem,那么 Grid 会自动变为 3 列 × 4 行。

要禁用自动增加行数,可以设置 rowsTemplate 为固定模式,并配合 Scroll 组件来实现滚动。对于九宫格,我们恰好是 3×3=9 项,刚好填满,没有溢出问题。


七、最佳实践与性能优化

7.1 数据驱动 UI

这是一个重要的 ArkTS 编程范式:永远通过修改数据来驱动 UI 变化,而非直接操作 DOM

✅ 推荐做法:

@State cells: GridCell[] = [...];
// 修改数据
this.cells[0] = { id: 1, label: '新值', color: '#FF0000' };
// UI 自动更新

❌ 不推荐(在 ArkTS 中也不允许):

// 不存在类似 setText() / setColor() 的直接 DOM 操作

7.2 使用稳定的键值

ForEach 的第三个参数中提供稳定的键值:

ForEach(this.cells, (item) => { ... }, (item) => item.id.toString())

为什么重要:当数组发生插入、删除、排序时,框架通过键值对比来决定哪些 GridItem 需要重建、哪些可以复用。使用 id 而非索引作为键值,可以避免不必要的 DOM 重建,提升列表性能。

7.3 Grid 的懒加载(LazyForEach)

当九宫格扩展为大量数据时(如 100×100 网格),应使用 LazyForEach 替代 ForEach

Grid() {
  LazyForEach(this.dataSource, (item: GridCell) => {
    GridItem() { /* ... */ }
  }, (item: GridCell) => item.id.toString())
}
.columnsTemplate('1fr 1fr 1fr')
// ...

LazyForEach 只渲染可见区域内的 GridItem,当用户滚动时动态创建和回收子组件,内存占用大幅降低。API 24 对 LazyForEach 的回收策略做了进一步优化,回收延迟更小、帧率更稳定。

7.4 避免 GridItem 嵌套过深

每个 GridItem 内部的组件树深度会影响布局性能。对于简单的格子,应尽量扁平:

✅ 推荐(1 层嵌套):

GridItem → Column → Text + Text

❌ 避免(3+ 层嵌套):

GridItem → Column → Row → Column → Text

在九宫格示例中,每个 GridItem 只嵌套了一层 Column,这是最佳实践。

7.5 使用 ResourceColor 而非魔法字符串

虽然示例中直接使用了十六进制颜色字符串(如 '#FF6B81'),但在正式项目中,建议将颜色定义在资源文件中并通过 $r() 引用:

// resources/base/element/color.json
{
  "color": [
    { "name": "grid_cell_1", "value": "#FF6B81" }
  ]
}

// 在代码中引用
.backgroundColor($r('app.color.grid_cell_1'))

这样做的好处:换肤支持、全局统一管理颜色、减小包体积。


八、扩展实战:从九宫格到更多布局

8.1 变成 4×4 宫格

只需修改一行代码:

.columnsTemplate('1fr 1fr 1fr 1fr')  // 4 列
.rowsTemplate('1fr 1fr 1fr 1fr')     // 4 行

同时将数据源增加到 16 项即可。这就是 Grid 的伸缩性——模板字符串描述布局结构,数据驱动内容。

8.2 非等宽九宫格(左侧窄导航 + 右侧宽内容)

.columnsTemplate('80vp 1fr 1fr')
.rowsTemplate('1fr 1fr 1fr')

第一列固定 80vp(适合做图标导航),后两列等分剩余空间(适合展示内容卡片)。

8.3 不规则网格(合并单元格)

ArkUI 的 GridItem 支持通过 columnStartcolumnEndrowStartrowEnd 属性实现跨行跨列:

GridItem() {
  Text('跨列')
    .width('100%').height('100%')
    .backgroundColor('#FF6B81')
    .textAlign(TextAlign.Center)
}
.columnStart(0)
.columnEnd(1)  // 从第 0 列跨越到第 1 列
.rowStart(0)
.rowEnd(0)

这可以实现类似"网格中的大图 banner"效果,非常适合九宫格中突出显示某个特定项。

8.4 结合 Scroll 实现可滚动的网格

当 GridItem 数量超过一屏时,将 Grid 放入 Scroll 组件中:

Scroll() {
  Grid() {
    ForEach(this.cells, (item) => {
      GridItem() { /* ... */ }
    })
  }
  .columnsTemplate('1fr 1fr 1fr')
  .rowsTemplate('1fr 1fr 1fr')  // 固定 3 行,多余项自动换到 "下一屏"
}
.scrollable(ScrollDirection.Vertical)

API 24 中 Scroll + Grid 的联动效率得到提升,滚动过程中的布局计算不再阻塞主线程。

8.5 Grid 与动画结合

利用 API 24 新增的 gap 动画能力,可以实现网格间距的动态变化:

@State gapValue: number = 8;

Grid() {
  // ...
}
.columnsGap(this.gapValue)
.rowsGap(this.gapValue)
// 通过点击按钮触发动画
Button('展开间距')
  .onClick(() => {
    animateTo({ duration: 300, curve: Curve.EaseInOut }, () => {
      this.gapValue = 24;  // 间距从 8vp 平滑过渡到 24vp
    });
  })

九、常见问题与排错

9.1 GridItem 不显示或显示异常

检查清单

  1. Grid 是否设置了 columnsTemplate?(必须设置,否则 GridItem 不会排列)
  2. GridItem 是否有明确的内容?(空的 GridItem 虽然存在但视觉不可见)
  3. 父容器是否有固定高度?(Grid 需要有确定的高度或通过约束计算出来)
  4. ForEach 的键值是否重复?(重复键值会导致渲染异常)

9.2 Grid 内容溢出或空白过多

原因rowsTemplate 设置的行数与 GridItem 数量不匹配。

  • 如果 GridItem 数量 > 行数 × 列数,Grid 会自动增加行,导致 rowsTemplate 的部分设定失效。
  • 如果 GridItem 数量 < 行数 × 列数,会留下空白格子。

解决方案:要么精确控制 GridItem 数量(如九宫格固定 9 项),要么使用 LazyForEach 适配动态数据。

9.3 各列宽度不一致

检查columnsTemplate 字符串中的 token 是否被正确解析。

// ✅ 正确:空格分隔
.columnsTemplate('1fr 1fr 1fr')

// ❌ 错误:逗号分隔(ArkUI 不支持)
.columnsTemplate('1fr, 1fr, 1fr')

// ❌ 错误:多余空格
.columnsTemplate('1fr  1fr 1fr')  // 双空格可能导致解析异常

9.4 性能问题:页面卡顿

诊断与优化

问题 解决方案
GridItem 中动画过多 减少不必要的动画,或使用 animateTo 替代逐帧状态更新
数据源过大 使用 LazyForEach 替代 ForEach
嵌套过深 保持 GridItem 内部不超过 2 层容器嵌套
不必要的状态更新 仅在需要 UI 变化时修改 @State 变量,避免频繁赋值

十、总结

本文通过一个完整的九宫格示例,系统性地讲解了 HarmonyOS NEXT ArkTS 中 Grid 容器组件 的核心用法。

知识要点回顾

  • Grid 是二维网格布局容器,通过 columnsTemplaterowsTemplate 控制行列结构。
  • fr 比例单位是构建响应式网格的关键,能够自动适配不同屏幕尺寸。
  • ForEach + 稳定键值实现高效列表渲染。
  • 圆角 + 渐变背景 + 阴影的"卡片三要素"提升视觉品质。
  • 数据驱动 UI 是 ArkTS 声明式编程的核心思想。

从九宫格出发,Grid 的能力远不止于此——它可以是相册矩阵、商品网格、仪表盘面板、画板像素网格……掌握了 Grid,就掌握了鸿蒙原生布局体系中重要的一块拼图。

希望本文能为你的鸿蒙开发之旅提供切实的帮助。如果你在实践中有任何疑问或发现更酷的 Grid 用法,欢迎一起交流探讨。


本文配套完整源码位于 app014/entry/src/main/ets/pages/Index.ets,可直接在 DevEco Studio 中打开运行。

Logo

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

更多推荐