在复杂的内容展示场景中,网格布局能让我们以行列的方式整齐排列元素。ArkUI 提供了 Grid 容器及其子项组件 GridItem,二者配合使用即可实现灵活的网格布局。本篇将从定义、属性、事件到完整示例,系统地介绍如何使用 GridGridItem


1. Grid 定义介绍

interface GridInterface {
  (scroller?: Scroller): GridAttribute;
}
  • scroller(可选):绑定一个 Scroller 控制器,以实现网格内容的可编程滚动。

一个 Grid 容器仅能包含 GridItem 作为子组件,其它类型组件会被忽略。

1.1 基本示例

@Entry @Component struct GridDemo {
  private data: string[] = ["1","2","3","4","5","6","7","8","9","10"];

  build() {
    Column({ space: 10 }) {
      Grid() {
        ForEach(data, (item) => {
          GridItem() {
            Text("Item " + item)
              .fontSize(18)
              .backgroundColor("#aabbcc")
              .width("100%")
              .height(70);
          }
        })
      }
      .columnsTemplate("1fr 1fr 1fr") // 均分为 3      .columnsGap(10)                 // 列间距 10vp
      .rowsGap(10)                    // 行间距 10vp
      .width("100%")
      .height(170)
      .backgroundColor(Color.Pink)
    }
    .padding(10)
    .width("100%")
    .height("100%");
  }
}
@Entry @Component class GridDemo {
    let data = Array(["1","2","3","4","5","6","7","8","9","10"])

    func build() {
      Column(10) {
        Grid() {
          ForEach(data, itemGeneratorFunc: { item, _ in
            GridItem() {
              Text("Item \(item)")
                .fontSize(18)
                .backgroundColor(0xaabbcc)
                .width(100.percent)
                .height(70)
            }
          })
        }
        .columnsTemplate("1fr 1fr 1fr")
        .columnsGap(10)
        .rowsGap(10)
        .width(100.percent)
        .height(170)
        .backgroundColor(0xffc0cb)
      }
      .padding(10)
      .width(100.percent)
      .height(100.percent)
    }
}

2. Grid 属性介绍

declare class GridAttribute<T> extends CommonMethod<T> {
  columnsTemplate(value: string): T;
  rowsTemplate(value: string): T;
  columnsGap(value: number | string | Resource): T;
  rowsGap(value: number | string | Resource): T;
  cachedCount(value: number): T;
}
属性 说明
columnsTemplate 定义列模板,如 "1fr 1fr 1fr" 表示 3 列均分;也可用不同比例 "1fr 2fr 1fr"
rowsTemplate 定义行模板,语法同 columnsTemplate,默认 1 行
columnsGap 列间距
rowsGap 行间距
cachedCount 预缓存子项数量,用于性能优化

“fr” 单位代表网格可用空间份数,多个“fr”组合可实现不同比例的分栏布局。


3. Grid 事件介绍

declare class GridAttribute<T> extends CommonMethod<T> {
  onScrollIndex(event: (firstVisibleIndex: number) => void): T;
}
  • onScrollIndex:当可视区的起始子项下标变化时触发回调,适合实现“懒加载”或“滚动到底部自动加载”功能。

4. GridItem 定义与属性

interface GridItemInterface {
  (): GridItemAttribute;
}

declare class GridItemAttribute<T> extends CommonMethod<T> {
  rowStart(value: number): T;
  rowEnd(value: number): T;
  columnStart(value: number): T;
  columnEnd(value: number): T;
  forceRebuild(value: boolean): T;
}
属性 说明
rowStart 当前项在网格中开始的行号(从 0 开始)
rowEnd 当前项在网格中结束的行号(不包含该行)
columnStart 当前项在网格中开始的列号
columnEnd 当前项在网格中结束的列号
forceRebuild 是否在重新构建时强制重建此节点,适用于需要动态变更布局的场景

4.1 跨行跨列示例

@Entry @Component struct GridSpanDemo {
  private data = Array.from({ length: 10 }, (_, i) => i);

  build() {
    Grid() {
      ForEach(data, (item, idx) => {
        GridItem() {
          Text("Item " + idx).fontSize(18).width("100%").height("100%")
        }
        // 第 2 个项(idx==1)跨两列
        .columnStart(idx == 1 ? 0 : 0)
        .columnEnd(idx == 1 ? 2 : 0)
        // 第 5 个项(idx==4)跨两行
        .rowStart(idx == 4 ? 0 : 0)
        .rowEnd(idx == 4 ? 2 : 0)
      })
    }
    .columnsTemplate("1fr 1fr 1fr")
    .rowsTemplate("1fr 1fr 1fr")
    .columnsGap(8)
    .rowsGap(8)
    .width("100%")
    .height(300)
    .backgroundColor(Color.LightGray)
  }
}

5. 完整示例:动态配置网格

下面示例展示了如何根据屏幕宽度和设定的行列数,计算每个网格单元大小,并为特定项配置跨行跨列布局。

@Entry @Component struct GridFullDemo {
  private screenWidth: number = px2vp(1080);
  private colCount: number = 4;
  private rowCount: number = 5;
  private gap: number = 10;
  private cellSize: number = (screenWidth - gap * (colCount + 1)) / colCount;
  private items: number[] = Array.from({ length: 18 }, (_, i) => i);

  build() {
    Column() {
      Grid() {
        ForEach(items, (item, idx) => {
          GridItem() {
            Text("Item " + idx)
              .fontSize(16)
              .textAlign(TextAlign.Center)
              .layoutWeight(1)
          }
          .width("100%")
          .height("100%")
          // 第 16 个跨两行
          .rowStart(idx == 15 ? 0 : 0)
          .rowEnd(idx == 15 ? 2 : 0)
          // 第 17 个跨两列
          .columnStart(idx == 16 ? 0 : 0)
          .columnEnd(idx == 16 ? 2 : 0)
        })
      }
      .columnsTemplate("1fr 1fr 1fr 1fr")
      .rowsTemplate("1fr 1fr 1fr 1fr 1fr")
      .columnsGap(gap)
      .rowsGap(gap)
      .padding({ left: gap, right: gap })
      .width("100%")
      .height(cellSize * rowCount + gap * (rowCount - 1))
    }
    .padding(10)
    .width("100%")
    .height("100%");
  }
}

6. 小结

  • Grid:通过 columnsTemplaterowsTemplate 灵活定义行列;
  • GridItem:可跨行跨列,将指定单元格占据更大空间;
  • 支持行列间距 (columnsGaprowsGap) 与滚动绑定 (scroller);
  • 结合 onScrollIndex 可实现懒加载等高级功能。

掌握了本篇内容,您即可在 ArkUI 中游刃有余地构建各种网格布局,满足不同屏幕和业务需求。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐