HarmonyOS ArkTS 网格布局(Grid Layout)详解
网格布局是界面布局中一个特别有用的方式,尤其当你希望把内容平铺成 规则行列结构 时,比如 相册图库、商品卡片列表、信息密集型仪表盘 等场景,一旦掌握了网格布局,它能让界面组织变得非常轻松。developer.huawei.com
一、什么是网格布局
在 ArkTS 的声明式 UI 体系里,Grid 容器 是一种二维布局方式,它不像 Row/Column 只有一条轴(水平/垂直),而是把页面划分成 固定的行和列。 你可以通过定义行、列的“分数”/比例,配合间距、单元格间隔等配置,让子组件在网格中均匀排列。Gitee
从设计角度看:
- 它能实现 规则的二维结构
- 子组件直接按格子位置分布
- 适合大批量、等间隔元素展示
- 是响应式布局里重要的一环,能适应不同尺寸屏幕developer.huawei.com
二、Grid 能解决什么问题
想象以下场景:
✔ 一堆商品卡片需要按 3 列排列 ✔ 图片墙需要自动按屏幕宽度排布 ✔ 你希望某些项目跨越多列或多行
如果用 Row/Column 嵌套写,会很绕:
Row → Column → Row → Column → ...
而 Grid 只需要一句:
按行列规则定义网格 → 把所有子项放进去即可
它的核心在于将界面拆分为有规律的 网格单元,然后让内容自动适配这些格子,从而减少嵌套层级和写样式的成本。Gitee
三、怎么写基本的 Grid
最简单的网格结构长这样:
@Entry
@Component
struct GridExample {
build() {
Grid() {
GridItem() { Text("1") }
GridItem() { Text("2") }
GridItem() { Text("3") }
GridItem() { Text("4") }
GridItem() { Text("5") }
GridItem() { Text("6") }
}
.rowsTemplate("1fr 1fr") // 两行
.columnsTemplate("1fr 1fr 1fr") // 三列
.rowsGap(10) // 行间距
.columnsGap(10) // 列间距
.width('100%')
.height(300);
}
}
解释一下:
Grid()是容器GridItem()是单个网格单元rowsTemplate("1fr 1fr")定义了 两行columnsTemplate("1fr 1fr 1fr")定义了 三列"fr"是 fraction(分数)单位,表示比例空间rowsGap和columnsGap则控制行列之间的间隔
这样写出来,是一个 2 × 3 的网格,每个格子的空间按行列权重平均分配。Gitee
四、rowsTemplate / columnsTemplate 的细节
1) 基于比例的布局
你可以写:
"1fr 1fr 1fr"→ 三等分"2fr 1fr"→ 第一行/列占 2 份宽度,第二份为 1 份
比如:
.columnsTemplate("2fr 1fr")
.rowsTemplate("1fr 2fr")
上面定义的是:
- 两列宽度比例是 2:1
- 两行高度比例是 1:2
这种写法非常适合你在视觉上想要某些格子更大、更醒目。Gitee
五、网格间距和样式常用属性
| 属性 | 作用 |
|---|---|
rowsGap(value) | 控制每一行之间的垂直间距 |
columnsGap(value) | 控制每一列之间的水平间距 |
gridStyle(...) | 给整个网格增加背景/边框/边距等样式 |
示例:
Grid()
.columnsTemplate("1fr 1fr 1fr")
.rowsTemplate("1fr 1fr")
.columnsGap(12)
.rowsGap(8)
.gridStyle({
backgroundColor: Color.White,
borderRadius: 8,
});
注意:
- 间距不是自动的,你必须主动设置,否则网格项之间挨得很近
因为每个行/列是等分的,所以合理设置间距能让 UI 看起来更清爽。kitemetric.com
六、什么时候用 Grid 比较合适
合适的场景包括:
1. 图片墙 / 图库
比如一个 3 列图库,每个图片都统一大小,这种情况最适合 Grid。
2. 商品卡片列表
你希望商品卡片在横屏/竖屏下都能等宽分布。
3. 仪表盘 / 统计面板
这种卡片型的结构很多时候是规则网格,看起来整齐统一。
不是所有网格都要用 Grid
如果你的布局只是简单的一行三列按钮,其实 Row + SpaceBetween 即可;只有当 UI 是“多行多列”的规则结构时,Grid 才真正凸显它的价值。
七、进阶:动态数据 + Grid
在实际项目中,我们往往不是手敲每个 GridItem,而是通过数组动态生成。典型写法是配合 ForEach 使用:
Grid() {
ForEach(this.items, (item) => {
GridItem() {
Text(item.title)
.fontSize(14)
.fontColor(Color.Black);
}
})
}
.rowsTemplate("repeat(3, 1fr)") // 重复三等分
.columnsGap(12)
.rowsGap(12)
相较于静态写法,动态渲染让你能轻松应对列表数据变化。kitemetric.com
八、响应式适配(高级)
官方也让 Grid 支持一种响应式适配思路(类似 CSS Grid + Breakpoints 概念):可以按屏幕尺寸自动调整列数。比如:
- 屏幕小 → 2 列
- 屏幕大 → 4 列
官方文档里提到在 GridRow/GridCol 的 响应式网格系统。[openharmony docs 镜像](它划分断点、可按设备宽度自动调整布局)。developer.huawei.com
虽然具体 API 可能需要看 breakpoints 的定义方式,但核心思路是:
先定义断点,再定义在各个断点下 columnsTemplate,最后让系统按屏幕宽度自动切换布局规则。
这种写法在多屏设备(手机/平板/大屏)中用得非常多。
九、实战小建议
下面这些是我做 UI 时经常踩坑的问题,也是你在用 Grid 时绝大多数能遇到的:
1. 不要忘记设置 rowsTemplate 或 columnsTemplate
如果没有设置任何行/列模板,Grid 不会按你预期展示。 它不会像 Flex 那样自动缩放每个子节点 —— 它本质上是按照模板去布局的。Gitee
2. 间距一定要设置
尤其是 columnsGap / rowsGap,不设置的话默认是 0,视觉上看起来会很挤。
3. 配合 Scroll 一起用
如果你的网格内容很多,记得把 Grid 放在一个可滚动的组件(如 Scroll)里,这样超出屏幕的内容才会滚动,否则会压缩得很难看。
十、总结(一句话)
Grid 布局是规则二维布局的最优解:它让你用一套模板声明出规律性的行列结构,再把内容填进去,而不用写一堆嵌套容器,适合展示“表格式、图库式、卡片式”的界面。
当你在项目里需要让元素在横纵方向都有一致的定位规则时,Grid 是最简洁可靠的工具。developer.hu