HarmonyOS ArkTS 创建网格 Grid/GridItem:写得顺、适配稳、滚动不卡的那套方法

鸿蒙第四期开发者活动

网格布局(Grid)不是“Row/Column 的升级版”,它更像是你在做 九宫格、相册墙、商品卡片 时的“标准答案”:用“行 + 列”把容器切成一个个单元格,然后把内容放进去。developer.huawei.com+1

这篇我按项目里真会遇到的顺序写:先把概念讲透,再给你三种最常见的写法(固定网格 / 可滚动网格 / 自适应网格),最后再讲几个一踩就痛的坑。


1)Grid 和 GridItem 到底是什么关系?

  • Grid():网格容器,负责“行列怎么分、间距多大、怎么滚动、怎么排列”。developer.huawei.com+1
  • GridItem():网格里的单元格项目,每一块内容都应该放在 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 往往就能形成滚动网格(官方和社区都把这当成常用方案)。CSDN博客+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 当成一个“小容器”,里面爱怎么排怎么排:

  1. 图片 + 标题 + 价格(电商卡片)
  2. 图标 + 文案(九宫格入口)
  3. 封面图 + 标签(相册/视频墙)

关键是: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
Logo

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

更多推荐