鸿蒙原生 ArkTS 弹性布局体系完全指南:从 Flex/Stack 到 Grid 的 12 种布局实战

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一、引言

HarmonyOS NEXT 作为鸿蒙生态的里程碑版本,从系统底层剔除了 Android 代码,实现了真正意义上的「纯鸿蒙」。与之配套的 ArkUI 框架提供了一套完整的声明式 UI 布局体系,其核心设计理念是 「弹性」—— 即布局容器和子组件能够根据可用空间自动调整尺寸和排列方式,从而适配从智能手表(320px)到折叠屏展开态(1440px)的各种屏幕尺寸。

ArkUI 的布局体系可以归纳为三大类容器:

  1. Flex 弹性容器:一维排列,支持水平/垂直/反向四种方向,弹性伸缩(flexGrow/flexShrink/flexBasis)
  2. Stack 层叠容器:Z 轴堆叠,支持 9 种对齐位置,适合盖层/浮层场景
  3. Grid 网格容器:二维排列,通过 columnsTemplate/rowsTemplate 精确控制行列结构

本文将以一个完整的鸿蒙应用项目为依托,逐一深入讲解这三大类容器的 12 种布局模式,包含完整的代码示例、布局公式和典型应用场景。


二、项目架构与入口

2.1 应用入口 EntryAbility

鸿蒙应用的入口是 UIAbility 的子类,通过 onWindowStageCreate 生命周期加载首页面:

// entry/src/main/ets/entryability/EntryAbility.ets
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { window } from '@kit.ArkUI';

const DOMAIN = 0x0000;

export default class EntryAbility extends UIAbility {
  onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
    hilog.info(DOMAIN, 'EnglishApp', 'Ability onCreate');
  }

  onDestroy(): void {
    hilog.info(DOMAIN, 'EnglishApp', 'Ability onDestroy');
  }

  onWindowStageCreate(windowStage: window.WindowStage): void {
    hilog.info(DOMAIN, 'EnglishApp', 'Ability onWindowStageCreate');
    windowStage.loadContent('pages/GridFixedColDemo', (err) => {
      if (err.code) {
        hilog.error(DOMAIN, 'EnglishApp',
          'Failed to load content: %{public}s', JSON.stringify(err));
        return;
      }
      hilog.info(DOMAIN, 'EnglishApp', 'Succeeded in loading content.');
    });
  }

  onWindowStageDestroy(): void { /* ... */ }
  onForeground(): void { /* ... */ }
  onBackground(): void { /* ... */ }
}

要点

  • loadContent 参数为页面路径(不含 .ets 后缀)
  • 框架自动解析路径并加载对应页面
  • hilog 来自 @kit.PerformanceAnalysisKit,是鸿蒙的日志工具

2.2 页面结构通用模板

每个演示页面都采用一致的骨架结构:

最外层 Column(height:100%, width:100%)
├── 顶部标题栏(蓝底白字,固定高度)
└── Scroll 滚动区
    └── 内层 Column
        ├── DemoSection 演示区块 1
        ├── DemoSection 演示区块 2
        ├── ...
        └── TechPanel 技术说明面板

三、Column 主轴对齐布局

3.1 核心概念

Column 是 ArkUI 中最基础的垂直布局容器。它的主轴(Main Axis)方向是「从上到下」,交叉轴(Cross Axis)方向是「从左到右」。justifyContent 控制主轴方向的对齐方式,alignItems 控制交叉轴方向的对齐方式。

3.2 6 种对齐值

枚举值效果类比 CSS
FlexAlign.Start顶部起始排列flex-start
FlexAlign.Center垂直居中center
FlexAlign.End底部对齐flex-end
FlexAlign.SpaceBetween两端对齐,子项间等距space-between
FlexAlign.SpaceAround每个子项左右间距相等space-around
FlexAlign.SpaceEvenly子项间及两端间距相等space-evenly

3.3 代码实现

@Entry
@Component
struct ColumnStartPage {
  private readonly infoList: InfoItem[] = [
    { title: '📌 系统通知', desc: '您的鸿蒙应用已通过安全检测。' },
    { title: '📊 数据报告', desc: '本周活跃用户增长 12%。' },
    { title: '⚙️ 版本更新', desc: 'v3.2.0 发布。' },
    { title: '🎯 优化建议', desc: '检测到 3 处可优化项。' },
  ];

  build() {
    Column() {
      // 标题区
      Column() { /* ... */ }
        .backgroundColor('#2d5f8a')

      // ★ 核心:Column + justifyContent(Start) ★
      Column() {
        ForEach(this.infoList, (item, idx) => {
          InfoCard({ item, index: idx })
        })
      }
      .alignItems(HorizontalAlign.Start)      // 交叉轴左对齐
      .justifyContent(FlexAlign.Start)        // ★ 主轴从顶部开始 ★
      .width('100%')
      .layoutWeight(1)                         // 撑满剩余高度
    }
    .width('100%').height('100%')
    .backgroundColor('#eef2f7')
  }
}

关键理解layoutWeight(1) 让 Column 占满父容器剩余高度,这样才能让 justifyContent 的效果可见。如果 Column 高度等于内容高度,Start/Center/End 看不出区别。


四、Flex 弹性容器与四种 flexDirection

Flex 是比 Column/Row 更底层、更灵活的弹性容器。Column 等效于 flexDirection(FlexDirection.Column) 的 Flex 容器,Row 等效于 flexDirection(FlexDirection.Row) 的 Flex 容器。但 Flex 额外支持两种反向模式。

4.1 四种方向一览

flexDirection 值排列方向代码首项位置典型场景
FlexDirection.Row从左→右最左侧水平导航栏
FlexDirection.RowReverse从右→左最右侧RTL语言界面
FlexDirection.Column从上→下最顶部表单/纵向列表
FlexDirection.ColumnReverse从下→上最底部聊天消息列表

4.2 Row 与 RowReverse 对比

// ★ Row:从左到右 ★
Flex() {
  Text('A'), Text('B'), Text('C')
}
.flexDirection(FlexDirection.Row)
// 输出:[A] [B] [C]

// ★ RowReverse:从右到左 ★
Flex() {
  Text('A'), Text('B'), Text('C')
}
.flexDirection(FlexDirection.RowReverse)
// 输出:[C] [B] [A]  ← 代码在前的 A 显示在右侧

4.3 ColumnReverse 的聊天列表应用

ColumnReverse 最经典的场景是聊天消息列表——最新消息在底部,历史消息在上方:

Flex() {
  // 最早的消息在代码顶部,显示在列表顶部
  ChatBubble({ msg: '早上好!', isSelf: false })
  ChatBubble({ msg: '下午三点开会。', isSelf: true })
  // ★ 最新消息在代码最后 → 显示在最底部 ★
  ChatBubble({ msg: '好的,准时到。', isSelf: false })
}
.flexDirection(FlexDirection.ColumnReverse)

容易混淆的点

  • RowReverse 只反转排列顺序,不反转每个组件内部的内容方向
  • justifyContent(FlexAlign.Start) 在 RowReverse 下等效于「右侧对齐」
  • alignItems 不受反向影响,始终控制交叉轴方向

五、Flex + Wrap 响应式卡片流

当子组件数量多到一行放不下时,普通的 Flex(不换行)会尝试压缩所有子组件以适应容器宽度。而在电商、图库等场景中,我们希望子组件在空间不足时自动「换行」到下一行——这就是 flexWrap(FlexWrap.Wrap) 的作用。

5.1 核心代码结构

Flex() {
  ForEach(PRODUCTS, (product) => {
    ProductCard({ product, cardSizeMode: this.cardSizeMode })
  })
}
.flexDirection(FlexDirection.Row)        // 主轴水平
.flexWrap(FlexWrap.Wrap)                 // ★ 允许换行(核心)★
.justifyContent(FlexAlign.Start)         // 行内左对齐
.alignItems(ItemAlign.Start)             // 交叉轴顶部对齐
.width('100%')

5.2 layoutWeight 实现等分

每个卡片组件使用 layoutWeight(1) 控制行内宽度比例:

@Component
struct ProductCard {
  @Link cardSizeMode: number;   // 0=小(3列) / 1=中(2列) / 2=大(1列)

  build() {
    Column() {
      Text(this.product.emoji).fontSize(this.cardSizeMode === 2 ? 36 : 26)
      Text(this.product.name)
        .fontSize(this.cardSizeMode === 2 ? 18 : 14)
      Text(`¥${this.product.price}`)
        .fontSize(this.cardSizeMode === 2 ? 22 : 18)
        .fontColor('#e74c3c')
    }
    .layoutWeight(1)                    // ★ 同一行中等分宽度 ★
    .margin(6)
  }
}

5.3 flexGrow vs layoutWeight

属性分配对象公式
flexGrow剩余空间(容器 − 所有子项内容尺寸)内容宽 + 剩余空间 × (growN / Σgrow)
layoutWeight容器全部空间容器宽 × (weightN / Σweight)

在换行布局中,layoutWeight 更常用,因为每行独立计算权重分配,不受其他行子项内容宽度干扰。

5.4 @State 驱动密度切换

@State cardSizeMode: number = 0;

Row() {
  ForEach([0, 1, 2], (mode: number) => {
    Button(['紧凑(3列)', '适中(2列)', '宽大(1列)'][mode])
      .layoutWeight(1)
      .backgroundColor(this.cardSizeMode === mode ? '#2d5f8a' : '#e8ecf0')
      .onClick(() => { this.cardSizeMode = mode; })
  })
}

六、Flex + flexGrow 弹性增长

flexGrow 是弹性布局中最重要的单个属性。它定义了子组件在「剩余空间」中的分配比例。

6.1 核心公式

子项 N 的实际增长量 = 剩余空间 × (growN ÷ Σgrow)

其中:
  剩余空间 = 容器主轴尺寸 − 所有子组件内容尺寸之和(或 flexBasis 之和)
  Σgrow = 所有非零 flexGrow 值的总和

6.2 基础:单项填充

Flex() {
  Text('A:grow(0)')  // 不增长,只占内容宽度
  Text('B:grow(0)')  // 不增长
  Text('C:grow(1)')  // ★ 填充所有剩余空间 ★
}
.flexDirection(FlexDirection.Row)
.width('100%')

这是「固定左 + 固定右 + 弹性中间」布局模式的实现原理。

6.3 等比分配

// 1:1:1 → 三等分剩余空间
.grow(1) : .grow(1) : .grow(1)
// 每项 = 剩余空间 × 1/3

// 1:2:1 → 中间是两边的 2 倍
.grow(1) : .grow(2) : .grow(1)
// A = 剩余空间 × 1/4
// B = 剩余空间 × 2/4 = 1/2
// C = 剩余空间 × 1/4

6.4 垂直方向的页面骨架

Flex() {
  Row() {}.flexGrow(0).height(48)    // 顶部固定
  Column() {}.flexGrow(1)            // ★ 内容区弹性填充 ★
  Row() {}.flexGrow(0).height(40)    // 底部固定
}
.flexDirection(FlexDirection.Column)
.height('100%')

这是移动端最经典的页面布局模式,flexGrow(1) 让中间内容区自动填满头尾之外的所有剩余高度。


七、Flex + flexBasis 基准尺寸

flexBasis 设置子组件在「弹性分配前」的主轴初始尺寸,flexGrow/flexShrink 在此之上叠加作用。

7.1 flexBasis 取值

含义示例
'auto'由内容或 width/height 决定.flexBasis('auto')
'80px'固定初始尺寸 80vp.flexBasis('80px')
'33%'初始尺寸为容器主轴尺寸的 33%.flexBasis('33%')

7.2 最终尺寸公式

最终尺寸 = flexBasis + 增长量(grow) − 压缩量(shrink)

7.3 实战:三种典型布局模式

// ★ 模式1:固定左栏 + 弹性右栏 ★
Flex() {
  Column() {}.flexBasis('80px').flexGrow(0)    // 侧栏固定宽
  Column() {}.flexBasis('auto').flexGrow(1)    // 主区弹性填充
}
.flexDirection(FlexDirection.Row)

// ★ 模式2:三等分百分比布局 ★
Flex() {
  Column() {}.flexBasis('33.3%').flexGrow(0)
  Column() {}.flexBasis('33.3%').flexGrow(0)
  Column() {}.flexBasis('33.3%').flexGrow(0)
}
.flexDirection(FlexDirection.Row)

// ★ 模式3:垂直页面骨架(basis+flexGrow 混合)★
Flex() {
  Row() {}.flexBasis('56px').flexGrow(0)       // 顶栏固定高
  Column() {}.flexBasis('auto').flexGrow(1)    // 内容区弹性
  Row() {}.flexBasis('48px').flexGrow(0)       // 底栏固定高
}
.flexDirection(FlexDirection.Column).height('100%')

7.4 flexBasis + flexShrink 压缩演示

当容器宽度不足以容纳所有子项的 flexBasis 之和时,flexShrink 控制各子项的压缩比例:

Flex() {
  // A: shrink(0) → 不缩小,保持 100px
  Box({ label:'A', basis:'100px', shrink:0 })
  // B/C/D: shrink(1) → 各承担 1/3 溢出量
  Box({ label:'B', basis:'100px', shrink:1 })
  Box({ label:'C', basis:'100px', shrink:1 })
  Box({ label:'D', basis:'100px', shrink:1 })
}
.flexDirection(FlexDirection.Row)
.width(300)   // 4×100=400px > 300px,溢出 100px
// A:100px, B≈67px, C≈67px, D≈67px

八、Stack 层叠布局(四种对齐模式)

Stack 是 ArkUI 中的层叠容器——子组件沿 Z 轴堆叠而非沿 X/Y 轴排列。后写的子组件覆盖在先写的上方。alignContent 控制所有子组件整体的对齐位置。

8.1 9 种 Alignment 枚举

水平\垂直TopCenterBottom
StartTopStart 左上Start 左中BottomStart 左下
CenterTopCenter 上中Center 正中BottomCenter 下中
EndTopEnd 右上End 右中BottomEnd 右下

8.2 TopStart(左上对齐)

所有子组件对齐到 Stack 容器的左上角:

Stack() {
  StackBox({ w:200, h:150, color:'#5B9BD5', label:'底层' })
  StackBox({ w:160, h:100, color:'#70AD47', label:'中层' })
  StackBox({ w:100, h:80, color:'#FFC000', label:'★ 顶层' })
}
.alignContent(Alignment.TopStart)
.width('100%').height(160)

8.3 Top(顶部居中)

所有子组件水平居中、垂直贴顶:

Stack() {
  // 底层:横条背景
  Row() {}.width('100%').height(64).backgroundColor('#2d5f8a')
  // 中层:标题文字(顶部居中)
  Text('📢 系统通知').fontSize(16).fontColor('#ffffff')
  // 顶层:关闭按钮(右上角,突破居中约束)
  Text('✕').alignSelf(ItemAlign.End).margin({ top:8, right:14 })
}
.alignContent(Alignment.Top)
.width('100%').height(64)

8.4 Bottom(底部居中)

所有子组件水平居中、垂直贴底:

Stack() {
  // 底层:播放器面板
  Column() {}.width('100%').height(160).backgroundColor('#1a1a2e')
  // 上层:歌曲信息
  Row() { Text('🎵'), Text('歌名') }
  // 最上层:控制按钮
  Row() { Text('⏮'), Text('⏸'), Text('⏭') }
}
.alignContent(Alignment.Bottom)
.width('100%').height(170)

8.5 Overlay(层叠盖层 + ZIndex)

在图片上叠加文字、按钮、标签,并通过 ZIndex(n) 精确控制各层的前后关系:

Stack() {
  // L1: 底层图片
  ImageScreen()

  // L2: 半透明蒙层(zIndex=1)
  Column() {}.width('100%').height('100%')
    .backgroundColor('#22000000').zIndex(1)

  // L3: 左上标签(zIndex=2)
  Text('👟 运动鞋').alignSelf(ItemAlign.Start)
    .margin(10).zIndex(2)

  // L4: 右上评分(zIndex=3)
  Text('⭐ 4.8').alignSelf(ItemAlign.End)
    .margin(10).zIndex(3)

  // L5: 底部价格条(zIndex=5,最上层)
  Row() { Text('¥ 1,299').fontColor('#e74c3c') }
    .alignSelf(ItemAlign.End).width('100%')
    .zIndex(5)
}
.alignContent(Alignment.TopStart)

ZIndex 规则

  • ZIndex(n) 数值越大,子组件越靠前(越在视觉上层)
  • 相同 ZIndex 时,后写的覆盖先写的
  • 无 ZIndex 时默认值为 0

8.6 alignSelf 覆盖整体对齐

在 Stack 中,可以通过 alignSelf 让某个子组件突破整体对齐约束,单独对齐到不同位置:

Stack() {
  Box('A:跟随')                     // 默认跟随 TopStart
  Box('B:左上').alignSelf(ItemAlign.Start)   // 覆盖为左上
  Box('C:右上').alignSelf(ItemAlign.End)     // 覆盖为右上
}
.alignContent(Alignment.Top)

8.7 position 精准定位

Stack() {
  PositionDot({ x:'10%', y:'10%', label:'A(10%,10%)' })
  PositionDot({ x:'50%', y:'30%', label:'B(50%,30%)' })
  PositionDot({ x:'80%', y:'60%', label:'C(80%,60%)' })
}
.alignContent(Alignment.TopStart)

.position({x, y}) 以 Stack 左上角为原点,支持像素和百分比两种单位。


九、Grid 固定列网格布局

Grid 是 ArkUI 最强大的二维布局容器,通过 columnsTemplaterowsTemplate 同时控制行和列的结构。

9.1 核心语法

Grid() {
  GridItem() { /* 第1行第1列 */ }
  GridItem() { /* 第1行第2列 */ }
  GridItem() { /* 第1行第3列 → 自动换行到第2行 */ }
  // ...更多 GridItem
}
.columnsTemplate('1fr 1fr 1fr')   // ★ 三列等宽 ★
.columnsGap(8)                      // 列间距
.rowsGap(8)                         // 行间距
.width('100%')

9.2 fr 单位详解

fr(fraction)是 Grid 中按比例分配空间的核心单位:

模板含义
'1fr 1fr 1fr'三列等宽,各占 1/3
'1fr 2fr 1fr'中间列是两侧的 2 倍
'80px 1fr 1fr'第一列固定 80px,后两列等分剩余
'1fr 1fr 1fr 1fr'四列等宽

9.3 混合列宽实战

Grid() {
  ForEach(items, (item) => {
    GridItem() {
      Column() {
        Text(item.label)
      }.width('100%').height(56)
      .backgroundColor(colors[idx]).borderRadius(8)
    }
  })
}
.columnsTemplate('80px 1fr 1fr')    // ← 固定+弹性混合
.columnsGap(6).rowsGap(6)
.width('100%')

9.4 GridItem 跨列

Grid() {
  // ★ 横幅:跨 3 列(占据整行宽度)★
  GridItem() {
    Text('🎉 限时特惠 · 全场满 300 减 50')
  }
  .columnStart(1).columnEnd(3)       // 跨第1到第3列

  // 普通商品卡片
  ForEach(PRODUCTS, (product) => {
    GridItem() { ProductCard(product) }
  })
}
.columnsTemplate('1fr 1fr 1fr')

columnStart/columnEnd 从 1 开始编号。columnEnd(3) 表示到第 3 列结束,即占据第 1-3 列的宽度。

9.5 商品网格完整示例

const PRODUCTS = [
  { name:'蓝牙耳机', price:299,  sold:18324, emoji:'🎧' },
  { name:'充电宝',   price:99,   sold:47531, emoji:'🔋' },
  { name:'智能手表', price:1299, sold:6592,  emoji:'⌚' },
  // ...更多商品
];

Grid() {
  ForEach(PRODUCTS, (product) => {
    GridItem() {
      Column() {
        Text(product.emoji).fontSize(28)
        Text(product.name).fontSize(13).fontWeight(FontWeight.Bold)
        Text(`¥${product.price}`).fontSize(18).fontColor('#e74c3c')
        Text(`已售 ${product.sold}`).fontSize(10).fontColor('#999')
      }
      .width('100%').height(130)
      .backgroundColor('#ffffff').borderRadius(10)
    }
  })
}
.columnsTemplate('1fr 1fr 1fr')
.columnsGap(8).rowsGap(8)
.width('100%')

十、布局属性速查表

10.1 Flex 弹性属性

属性作用于默认值取值类比 CSS
flexGrow子组件0number(≥0)flex-grow
flexShrink子组件1number(≥0)flex-shrink
flexBasis子组件'auto'number / stringflex-basis
flexWrap容器NoWrapNoWrap / Wrapflex-wrap
justifyContent容器Start6 种对齐值justify-content
alignItems容器Stretch4 种对齐值align-items
layoutWeight子组件0number无直接对应

10.2 Stack 层叠属性

属性作用取值
alignContent控制所有子组件整体对齐9 种 Alignment 枚举
alignSelf单个子组件突破整体对齐ItemAlign.Start / Center / End
zIndex显式控制 Z 轴顺序number(越大越靠前)
position以左上角为原点精准定位{x, y} 支持像素和百分比

10.3 Grid 网格属性

属性作用示例
columnsTemplate定义列宽模板'1fr 1fr 1fr'
rowsTemplate定义行高模板'1fr 1fr'
columnsGap列间距number
rowsGap行间距number
columnStart / columnEndGridItem 跨列number(从 1 开始)
rowStart / rowEndGridItem 跨行number(从 1 开始)

十一、常见布局陷阱与解决方案

11.1 flexGrow 不生效

原因:容器没有设置主轴的明确尺寸,或容器尺寸刚好等于子项内容尺寸
解决:确保容器有明确主轴尺寸(width/height),或使用 layoutWeight

11.2 子项溢出容器

原因:flexShrink 默认是 1,但如果所有子项 shrink 都是 0,则不会缩小
解决:给需要压缩的子项设置 flexShrink(1)

11.3 Wrap 不换行

原因:flexWrap 默认为 NoWrap
解决:显式设置 .flexWrap(FlexWrap.Wrap)

11.4 Stack 中子组件对齐方向混淆

误区:以为 Stack(TopStart) 中的子组件一定在左上角
正解:alignSelf 可以突破整体对齐。alignSelf(End) 会让子组件到右下角
记忆法:alignContent = 整体对齐,alignSelf = 个体突破

11.5 ColumnReverse 下 justifyContent 方向

误区:以为 Start 仍然是「顶部」
正解:ColumnReverse 下 Start = 底部,End = 顶部
记忆法:Start 永远指向主轴的「起始方向」

十二、性能优化建议

12.1 避免深层嵌套

Flex/Stack/Grid 容器可以嵌套,但建议深度控制在 3-4 层以内。过深的布局树会让 ArkUI 的布局引擎在每次状态变化时产生更多计算开销。

12.2 合理使用 layoutWeight

在卡片列表中使用 layoutWeight 比逐个计算百分比更高效,因为其分配算法在框架层是高度优化的。

12.3 @State 作用域最小化

@State 的变化会触发所在组件的 build() 重渲染,尽量将状态作用域限制在真正需要更新的层级。

12.4 懒加载长列表

当 Grid 或 Flex 中的子项超过 20 项时,考虑使用 LazyForEach 替代 ForEach 实现按需渲染:

LazyForEach(this.dataSource, (item) => {
  GridItem() { ProductCard(item) }
})

12.5 阴影的性能成本

过多的 shadow 会影响滚动性能。建议对长列表卡片组使用较轻柔的阴影(color: '#10000000'),或仅对焦点卡片应用阴影。


十三、设计理念总结

回顾本文涉及的 12 种布局模式,可以归纳出鸿蒙 ArkUI 弹性布局的三条核心设计哲学:

1. 永远不用固定尺寸

能用 flexGrowlayoutWeightflexBasis 的地方,就不要写 width(100)height(200)。弹性布局的本质是让空间分配自适应,而非硬编码。

2. 拥抱「剩余空间」思维

弹性布局的核心是对容器「剩余空间」的分配。flexGrow 分配剩余空间,layoutWeight 重算全部空间,flexBasis 定义初始起点。理解这三个概念,弹性布局就不再是魔法。

3. 选对容器,事半功倍

需求推荐容器
一维排列(水平/垂直)Flex + flexDirection
一维换行Flex + flexWrap(Wrap)
层叠覆盖Stack
二维表格/网格Grid
简单垂直排列Column(Flex 的语法糖)
简单水平排列Row(Flex 的语法糖)

附录:项目文件结构

MyApplication/
├── AppScope/
│   ├── app.json5
│   └── resources/
├── entry/
│   └── src/main/ets/
│       ├── entryability/
│       │   └── EntryAbility.ets          # 应用入口
│       └── pages/
│           ├── Index.ets                 # Column + justifyContent 演示
│           ├── GridFixedColDemo.ets      # Grid 固定列网格演示
│           └── RunnerPage.ets            # 跑酷游戏页
├── build-profile.json5                  # 构建配置(SDK 24)
└── hvigorfile.ts                        # 构建脚本

项目构建配置指定了 targetSdkVersion: "6.1.1(24)",所有代码均在该 SDK 版本下编译通过。


结语

鸿蒙原生 ArkTS 的弹性布局体系——从 Flex 的四种方向、弹性伸缩、换行流式排列,到 Stack 的九种对齐、ZIndex 层叠控制,再到 Grid 的网格模板与跨列——为开发者提供了一套完备、高效、声明式的 UI 布局方案。

掌握这些布局模式后,你会发现:布局不再是与屏幕尺寸的博弈,而是对空间优雅的分配。 在多设备、多尺寸的鸿蒙生态中,弹性布局是你构建优秀用户体验的基石。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值