HarmonyOS ArkTS 创建网格 Grid/GridItem:写得顺、适配稳、滚动不卡的那套方法
网格布局(Grid)不是“Row/Column 的升级版”,它更像是你在做 九宫格、相册墙、商品卡片 时的“标准答案”:用“行 + 列”把容器切成一个个单元格,然后把内容放进去。developer.huawei.com+1
这篇我按项目里真会遇到的顺序写:先把概念讲透,再给你三种最常见的写法(固定网格 / 可滚动网格 / 自适应网格),最后再讲几个一踩就痛的坑。
1)Grid 和 GridItem 到底是什么关系?
Grid():网格容器,负责“行列怎么分、间距多大、怎么滚动、怎么排列”。developer.huawei.com+1GridItem():网格里的单元格项目,每一块内容都应该放在 GridItem 里。官方也强调 Grid 的子组件是 GridItem。developer.huawei.com+1
你可以把它理解成:
Grid 负责“铺地砖”,GridItem 负责“在每块砖上放东西”。
2)先把“网格怎么分”的思路掰直:rowsTemplate / columnsTemplate
Grid 最核心的两句话就是:
rowsTemplate(...):定义有几行,每一行占多少“比例”columnsTemplate(...):定义有几列,每一列占多少“比例”Gitee+1
它们的值通常是这样的字符串:
.columnsTemplate('1fr 1fr 1fr')
.rowsTemplate('1fr 2fr')
这里的 fr 可以理解为“份数”(比例单位):
1fr 1fr 1fr= 三列等分1fr 2fr= 两行,第二行高度是第一行的 2 倍Gitee+1
行列间距:rowsGap / columnsGap
rowsGap(n):行与行之间的间距columnsGap(n):列与列之间的间距Gitee+1
3)最常用的三种网格写法(基本覆盖 80% 页面)
A. 固定网格:行列都写死(最稳、最适合“九宫格/计算器/日历”)
这种写法最“可控”:几行几列固定,布局结构一眼就能看懂。
@Entry
@Component
struct GridFixedDemo {
build() {
Column({ space: 12 }) {
Text('固定网格:2 行 x 3 列').fontSize(16).fontWeight(FontWeight.Medium)
Grid() {
ForEach([1,2,3,4,5,6], (n: number) => {
GridItem() {
Text(`${n}`)
.width('100%')
.height('100%')
.fontSize(18)
.fontWeight(FontWeight.Bold)
.textAlign(TextAlign.Center)
.backgroundColor(0xFFFFFFFF)
.borderRadius(12)
}
}, (n: number) => `${n}`)
}
.rowsTemplate('1fr 1fr')
.columnsTemplate('1fr 1fr 1fr')
.rowsGap(10)
.columnsGap(10)
.height(220)
.width('100%')
}
.padding(12)
.backgroundColor(0xFFF5F6F8)
.width('100%')
.height('100%')
}
}
这种“行列都设置”的场景,结构固定、好设计、好测 UI。官方创建网格文档也主要围绕 rowsTemplate/columnsTemplate 来说明。Gitee+1
B. 可滚动网格:只设置一个模板,让 Grid 自己滚动(文件管理/商品流最常见)
这个点很多人第一次会误会:
Grid 并不是一定要自己套 Scroll。 当你“只设置一个维度模板”时,Grid 往往就能形成滚动网格(官方和社区都把这当成常用方案)。优快云博客+1
竖向滚动网格(常用:只设置 columnsTemplate)
@Entry
@Component
struct GridScrollVerticalDemo {
@State items: number[] = Array.from({ length: 60 }, (_, i) => i + 1)
build() {
Grid() {
ForEach(this.items, (n: number) => {
GridItem() {
Column({ space: 6 }) {
// 模拟“商品卡片”
Rect().width('100%').height(70).fill(0xFFEAF2FF).radius(12)
Text(`商品 #${n}`).fontSize(14)
Text('¥ 99.00').fontSize(12).fontColor(0xFF888888)
}
.padding(10)
.backgroundColor(0xFFFFFFFF)
.borderRadius(12)
}
}, (n: number) => `${n}`)
}
.columnsTemplate('1fr 1fr') // 两列
.columnsGap(10)
.rowsGap(10)
.padding(12)
.backgroundColor(0xFFF5F6F8)
.width('100%')
.height('100%')
}
}
你会发现:项目多到超出屏幕后,Grid 会按列规则继续排,页面自然就变成“可滚动商品流”。
C. “看起来像自适应”的网格:优先用 Responsive Grid(GridRow/GridCol)
如果你要做“跨设备适配”,例如:
- 手机 2 列
- 平板 4 列
- 大屏 6 列
这类更推荐使用 响应式网格系统 GridRow/GridCol(文档里把它归为 Responsive Grid Layout)。developer.huawei.com+1
你这次问的是
Grid/GridItem的创建,我就先把原理讲透;如果你要做“断点适配”,我可以再给你一篇专门写 GridRow/GridCol 的“手机/平板一套代码适配”的实战模板。
4)GridItem 里到底放什么?(项目里最常见的 3 种卡片结构)
你可以把 GridItem 当成一个“小容器”,里面爱怎么排怎么排:
- 图片 + 标题 + 价格(电商卡片)
- 图标 + 文案(九宫格入口)
- 封面图 + 标签(相册/视频墙)
关键是:GridItem 外面不用再套一堆布局容器去算宽高,网格的宽高由模板决定,你只要让子内容 width('100%')、卡片圆角、padding 做舒服就行。
5)性能和渲染:别等卡了才想起优化
当你网格项很多(比如几百上千)时,建议关注两点:
① 优先考虑懒加载思路(LazyForEach)
OpenHarmony 的文档里提到:GridItem 与 LazyForEach 配合时,子组件在 GridItem 创建时创建;而配合 ForEach/if 或父组件为 Grid 时,子组件在布局时创建。Gitee
简单说就是:
- 数据量大:考虑 LazyForEach(减少一次性创建的压力)
- 数据量小:ForEach 足够
② 让每个 item 有稳定 key
ForEach(data, builder, keyFn) 里的 keyFn 不要省:
稳定 key 能减少“刷新时整片重建”,滚动和更新都会更顺。
6)几个一踩就中招的坑(写 Grid 时很常见)
坑 1:GridItem 不铺满格子
很多人写 GridItem 只放 Text,结果格子看起来“空、挤、对不齐”。
经验做法是:卡片容器本身设 width('100%')、内容设 padding,视觉会稳。
坑 2:间距没设导致“挤成一坨”
rowsGap / columnsGap 不写默认就是 0,网格会贴得很紧。Gitee+1
坑 3:把 Grid 当成万能布局
Grid 很强,但它擅长的是“规则二维”。
像“一个卡片左图右文,下方再有按钮”的复杂自由布局,通常是 GridItem 内部用 Row/Column/Flex/Stack 组合,而不是用 Grid 去硬拼结构。
7)收尾总结
- Grid/GridItem 适合“规则二维内容展示”:九宫格、卡片墙、相册、商品流。developer.huawei.com+1
rowsTemplate/columnsTemplate决定“网格怎么分”,rowsGap/columnsGap决定“网格舒不舒服”。Gitee+1- 数据量大时,关注稳定 key 和懒加载(LazyForEach),滚动体验差距非常明显。Gitee
3438

被折叠的 条评论
为什么被折叠?



