ArkUI GridRow:响应式别靠猜屏幕宽度

举报
蓝瘦的蜕变 发表于 2026/08/03 14:10:17 2026/08/03
【摘要】 今天我们用 GridRow 和 GridCol 搭一个十二列栅格页面,先把 span、offset、order 和 gutter 这些最常用的能力看明白。 准备很简单:页面里只用 ArkUI 自带组件,不需要额外资源。我们把整行交给 GridRow,再让每个 GridCol 说明自己占几列。这样写比手算百分比舒服,也更

ArkUI GridRow:响应式别靠猜屏幕宽度

今天我们用 GridRow 和 GridCol 搭一个十二列栅格页面,先把 spanoffsetordergutter 这些最常用的能力看明白。

准备很简单:页面里只用 ArkUI 自带组件,不需要额外资源。我们把整行交给 GridRow,再让每个 GridCol 说明自己占几列。这样写比手算百分比舒服,也更容易改。

第一块先看 spancolumns: 12 表示一行分成十二份,span: 4 就是占四份,所以一行正好放三块。这里的重点不是数字多神奇,而是我们终于不用在 width('33%') 这种写法里来回试。

第二块看 offset。它会在当前列前面空出几列,适合做错位和居中。如果只是想让某块内容往右挪,不用再塞一个空白组件。

第三块看 order。它让显示顺序和代码顺序分开。一般来说别滥用,但遇到少量展示顺序调整时,它比大段挪代码更干净。

最后再把 gutteralignItems 放在一起看。gutter 统一处理格子间距,alignItems 处理同一行里不同高度内容的交叉轴对齐。你写卡片入口、数据面板、设置页分区时,大概率会反复用到这几个点。

你平时写响应式布局时,是更喜欢十二列栅格,还是直接用 Row/Column 一路排下去?这个问题没有标准答案,但不同项目里取舍会很不一样。

完整代码

class GridRowFeature {
  title: string
  desc: string
  color: string

  constructor(title: string, desc: string, color: string) {
    this.title = title
    this.desc = desc
    this.color = color
  }
}

@Entry
@Component
struct ArkUIGridRowDemo {
  private features: GridRowFeature[] = [
    new GridRowFeature('span 4', '一行三列,适合入口区', '#2563EB'),
    new GridRowFeature('span 6', '一行两列,信息更舒展', '#0F766E'),
    new GridRowFeature('span 12', '独占整行,适合重点内容', '#C2410C'),
    new GridRowFeature('offset', '留出起始空位,少套一层容器', '#7C3AED'),
    new GridRowFeature('order', '显示顺序可以和代码顺序分开', '#B45309'),
    new GridRowFeature('gutter', '列和行之间统一留白', '#1D4ED8')
  ]

  @Builder
  sectionTitle(title: string, desc: string) {
    Column({ space: 6 }) {
      Text(title)
        .fontSize(19)
        .fontWeight(FontWeight.Bold)
        .fontColor('#111827')
      Text(desc)
        .fontSize(13)
        .fontColor('#6B7280')
        .lineHeight(20)
    }
    .width('100%')
    .alignItems(HorizontalAlign.Start)
  }

  @Builder
  featureCard(item: GridRowFeature) {
    Column({ space: 8 }) {
      Text(item.title)
        .fontSize(17)
        .fontWeight(FontWeight.Bold)
        .fontColor(item.color)
      Text(item.desc)
        .fontSize(12)
        .fontColor('#4B5563')
        .lineHeight(18)
    }
    .width('100%')
    .height(92)
    .padding(12)
    .borderRadius(8)
    .backgroundColor('#F8FAFC')
    .border({ width: 1, color: '#E5E7EB' })
    .justifyContent(FlexAlign.Center)
    .alignItems(HorizontalAlign.Start)
  }

  @Builder
  orderTile(text: string, color: string) {
    Text(text)
      .fontSize(14)
      .fontWeight(FontWeight.Medium)
      .fontColor('#FFFFFF')
      .textAlign(TextAlign.Center)
      .width('100%')
      .height(56)
      .borderRadius(8)
      .backgroundColor(color)
  }

  build() {
    Scroll() {
      Column({ space: 22 }) {
        Column({ space: 8 }) {
          Text('ArkUI GridRow')
            .fontSize(28)
            .fontWeight(FontWeight.Bold)
            .fontColor('#111827')
          Text('响应式别靠猜屏幕宽度')
            .fontSize(16)
            .fontColor('#4B5563')
          Text('GridRow 把一行切成固定列数,GridCol 决定每块占几列。我们先用十二列栅格看清 span、offset、order 和 gutter 的位置。')
            .fontSize(14)
            .fontColor('#6B7280')
            .lineHeight(22)
        }
        .width('100%')
        .alignItems(HorizontalAlign.Start)

        this.sectionTitle('span:先决定每块占几列', 'columns 给整行定格数,span 给每个 GridCol 定宽度。')
        GridRow({ columns: 12, gutter: { x: 8, y: 8 } }) {
          GridCol({ span: 4 }) {
            this.featureCard(this.features[0])
          }

          GridCol({ span: 4 }) {
            this.featureCard(this.features[1])
          }

          GridCol({ span: 4 }) {
            this.featureCard(this.features[2])
          }
        }
        .width('100%')

        this.sectionTitle('offset:需要错位时,不用再塞空白 View', 'offset 会在当前列前面留出列宽,适合做居中卡片或局部错位。')
        GridRow({ columns: 12, gutter: { x: 8, y: 8 } }) {
          GridCol({ span: 6 }) {
            this.featureCard(new GridRowFeature('左侧 span 6', '先占掉半行', '#0F766E'))
          }

          GridCol({ span: 3, offset: 3 }) {
            this.featureCard(new GridRowFeature('offset 3', '前面空三列', '#7C3AED'))
          }

          GridCol({ span: 4, offset: 4 }) {
            this.featureCard(new GridRowFeature('居中感', '四列空位加四列内容', '#C2410C'))
          }
        }
        .width('100%')

        this.sectionTitle('order:代码顺序和显示顺序可以分开', '少量调整显示位置时,order 比挪动整段代码更直接。')
        GridRow({ columns: 12, gutter: { x: 8, y: 8 } }) {
          GridCol({ span: 4, order: 3 }) {
            this.orderTile('代码第 1 个 / order 3', '#1D4ED8')
          }

          GridCol({ span: 4, order: 1 }) {
            this.orderTile('代码第 2 个 / order 1', '#0F766E')
          }

          GridCol({ span: 4, order: 2 }) {
            this.orderTile('代码第 3 个 / order 2', '#C2410C')
          }
        }
        .width('100%')
        .alignItems(ItemAlign.Center)

        this.sectionTitle('gutter + alignItems:间距和交叉轴一起管', 'gutter 统一处理格子间距,alignItems 处理这一行里不同高度内容的对齐。')
        GridRow({ columns: 12, gutter: { x: 10, y: 10 } }) {
          GridCol({ span: 4 }) {
            Text('短卡片')
              .fontSize(14)
              .fontColor('#111827')
              .width('100%')
              .height(52)
              .borderRadius(8)
              .backgroundColor('#DBEAFE')
              .textAlign(TextAlign.Center)
          }

          GridCol({ span: 4 }) {
            Text('高一点的卡片')
              .fontSize(14)
              .fontColor('#111827')
              .width('100%')
              .height(86)
              .borderRadius(8)
              .backgroundColor('#CCFBF1')
              .textAlign(TextAlign.Center)
          }

          GridCol({ span: 4 }) {
            Text('普通卡片')
              .fontSize(14)
              .fontColor('#111827')
              .width('100%')
              .height(68)
              .borderRadius(8)
              .backgroundColor('#FED7AA')
              .textAlign(TextAlign.Center)
          }
        }
        .width('100%')
        .alignItems(ItemAlign.Center)
      }
      .width('100%')
      .padding({ left: 18, right: 18, top: 22, bottom: 32 })
    }
    .width('100%')
    .height('100%')
    .backgroundColor('#FFFFFF')
  }
}
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。