目 录

  1. 前言
  2. Flex 控件概论
  3. 核心代码实现
  4. 核心属性:Flex 与 Axis
  5. 比例的力量:flex 因子 (Flex Factor)
  6. 伸缩组件家族:Expanded, Flexible, Spacer
  7. Flex 布局约束逻辑流程图
  8. 伸缩组件特性对比表
  9. 鸿蒙实战:折叠屏适配的分栏比例策略
  10. 总结

前言

在现代移动 UI 开发中,屏幕分辨率的碎片化是一大挑战。特别是在 HarmonyOS 生态下,我们需要同时适配修长的手机、方正的折叠屏(展开态)以及超宽的平板设备。如果我们的布局只是死板地设定像素宽高,那么在不同设备上必然会出现大量的留白或内容溢出。

这时,Flex (弹性布局) 便成为了我们的“终极武器”。作为 RowColumn 的底层实现,Flex 提供了一套基于比例的空间分配方案。它不仅能让组件在不同尺寸的鸿蒙屏幕上按比例“呼吸”和伸缩,更通过 flex 因子实现了真正的响应式设计。本文将带你深度剖析 Flex 控件的比例逻辑,探索 SpacerFlexible 的妙用,助你构建出“能伸能屈”、完美适配全场景鸿蒙终端的弹性界面。


在这里插入图片描述

在这里插入图片描述

Flex 控件概论

Flex 是 Flutter 布局体系中最基础的多子布局(Multi-child layout)控件之一。它允许子组件沿水平或垂直轴线排列。实际上,我们在开发中常用的 Row 只是 direction: Axis.horizontalFlex,而 Column 则是 direction: Axis.verticalFlex


3. 核心代码实现

在响应式布局中,Flex 是处理动态比例分配的基石。以下是适配鸿蒙全场景设备的核心实现模版:

3.1 动态方向切换 (折叠屏/旋转适配)

// 根据屏幕宽高比自动切换水平或垂直排列
Flex(
  direction: MediaQuery.of(context).size.aspectRatio > 1.0 
             ? Axis.horizontal 
             : Axis.vertical,
  children: [
    Expanded(
      flex: 1,
      child: Container(color: Colors.blue.shade200, child: const Center(child: Text("侧边栏/顶部"))),
    ),
    Expanded(
      flex: 2,
      child: Container(color: Colors.white, child: const Center(child: Text("主内容区"))),
    ),
  ],
)

3.2 黄金比例间距 (Flex + Spacer)

// 在三个组件之间插入不同比例的弹性间距
Flex(
  direction: Axis.horizontal,
  children: [
    const Icon(Icons.star),
    const Spacer(flex: 1), // 占据 1 份空隙
    const Text("中间内容"),
    const Spacer(flex: 2), // 占据 2 份空隙
    const Icon(Icons.favorite),
  ],
)

4. 核心属性:Flex 与 Axis

Flex 的核心控制力来自于 direction

  • Axis.horizontal: 线性水平排列。
  • Axis.vertical: 线性垂直排列。

由于它比 Row/Column 更底层,因此在需要动态切换排列方向(如鸿蒙折叠屏从竖屏切换为横屏分栏)时,直接使用 Flex 并动态修改 direction 是最高效的做法。


比例的力量:flex 因子 (Flex Factor)

当一个子组件被包裹在 ExpandedFlexible 中时,它的 flex 属性就生效了。

  • 逻辑:父容器会统计所有子组件的 flex 总和,然后按比例切割主轴剩余空间。
  • 计算:如果 A 的 flex 为 1,B 的 flex 为 2,那么 A 占据 1 / 3 1/3 1/3,B 占据 2 / 3 2/3 2/3

伸缩组件家族:Expanded, Flexible, Spacer

5.1 Expanded:霸道的空间占有者

Expanded 继承自 Flexible,其 fit 属性默认为 FlexFit.tight。这意味着它必须填满分配给它的所有空间。

5.2 Flexible:佛系的自适应者

Flexiblefit 属性默认为 FlexFit.loose。它允许子组件小于分配的空间。如果子组件本身很小,Flexible 就不会强行拉伸它。

5.3 Spacer:隐形的弹簧间距

Spacer 本质上是一个没有子组件的 Expanded。它常用于在组件之间撑开一段按比例计算的空白区域。


Flex 布局约束逻辑流程图

下图展示了 Flex 容器如何精准分配地盘:

Expanded

Flexible

Flex 容器开始布局

锁定主轴方向 Axis

测量所有固定尺寸组件

计算主轴剩余总长度 L

统计所有子组件 flex 因子总和 Sum

计算单位比例长度 Unit = L / Sum

按 flex 因子分发地盘

是 Expanded 还是 Flexible?

强制填满 Unit * flex

允许不填满, 最大 Unit * flex

绘制层渲染

屏幕呈现弹性布局


伸缩组件特性对比表

为了更加合理的说明内容,下表总结了弹性家族成员的差异:

控件 底层类 默认 Fit 是否强制拉伸子组件 推荐场景
Expanded Flexible tight 必须填满剩余背景的区域
Flexible Flexible loose 内容长度不确定,需自适应时
Spacer Expanded tight N/A (透明) 在两个按钮间撑开均匀空隙

鸿蒙实战:折叠屏适配的分栏比例策略

在适配华为 Mate X 系列折叠屏时,常见的“黄金比例”布局如下:

Flex(
  direction: Axis.horizontal,
  children: [
    // 左侧:功能导航 (占 2 份)
    Expanded(flex: 2, child: SideNav()),
    // 右侧:主内容区 (占 3 份)
    Expanded(flex: 3, child: MainContent()),
  ],
)

这种设计能确保在折叠态(窄屏)和展开态(宽屏)下,视觉比例始终维持在完美的 2:3 比例,避免了界面因拉伸而失衡。


总结

Flex 控件是 Flutter 响应式设计的灵魂。它不仅通过 flex 因子解决了“地盘怎么分”的问题,更通过 ExpandedFlexible 的精妙配合,实现了逻辑与视觉的完美统一。在 HarmonyOS NEXT 的多元终端生态中,掌握了弹性布局,你就拥有了构建“全场景自适应”应用的底气。

记住,布局不是死板的像素堆砌,而是动态的空间治理。在掌握了弹性的奥秘后,下一篇我们将迎来交互领域的“感知大师”——GestureDetector (手势识别),学习如何让你的 UI 响应用户的每一次触摸与滑动。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐