近两年在 OpenHarmony 生态里用 Flutter 做应用开发,已经不算什么新鲜事了。社区维护的适配分支越来越成熟,很多原本跑在移动端的 Flutter 工程,经过少量改造就能跑到 OpenHarmony 设备上。我去年接手的一个模拟项目,就是把一套原本面向安卓的信息展示应用迁到 OpenHarmony 设备上,用的就是 Flutter for OpenHarmony 这套链路。整体迁移不算难,真正让我花时间打磨的,反而是最基础的 Column 垂直布局。
原因很简单:在 OpenHarmony 的多种屏幕形态下,Column 的排列规则、空间分配和溢出处理,比在单一手机尺寸上要敏感得多。很多在安卓模拟器上跑得好好的布局,到了 OpenHarmony 平板上就溢出;明明加了 Expanded,却还是报 RenderFlex overflowed。这篇文章就把我在这套环境下使用 Column 的经验和踩坑过程完整梳理一遍,从核心属性到实战案例,再到一条完整的排查链路。无论你是刚开始接触 Flutter for OpenHarmony,还是已经写完几个页面但被布局问题困扰,都能在这里找到可以直接抄作业的方案。
1. 为什么在 OpenHarmony 上用 Flutter:Column 的用武之地
1.1 Flutter 适配 OpenHarmony 的实践前提
首先要明确一点:OpenHarmony 上的 Flutter 并不是官方默认支持,而是通过社区适配分支来运行的。这个分支维护了 Flutter 引擎在 OpenHarmony 设备上的渲染能力,包括字体、输入法、平台通道等基础能力。不过在实际开发中,只要你用的是稳定版本适配分支,大部分 Flutter 组件都能正常工作。
我个人的建议是,适配分支优先做减法,也就是少用太新的 Flutter 特性,多用稳定组件。Column 这种基础布局组件,恰恰是最稳定、最不容易出问题的部分。也正因如此,把 Column 的细节吃透,能让你在 OpenHarmony 上避开大量布局深坑。
1.2 垂直布局在真实页面中的占比
如果你打开任意一个业务型应用,信息流页面、个人中心、商品详情、设置页,绝大多数都是垂直方向上的堆叠布局。可以说,Column 的熟练度直接决定了你写页面时的舒服程度。
我粗略统计过自己写的模拟项目页面:一个完整的信息展示页里,Column 配合文本、图片、按钮构成的垂直结构,大概占到整个页面布局的七成以上。横向布局当然也很重要,但大多是以 Row 的形式嵌在 Column 内部,作为某一个区块的横向内容排列。所以,Column 才是页面骨架中的主角。
1.3 一个典型页面的布局拆解
拿我改写的某个信息展示页举例,整体页面从上到下的结构是:
- 顶部标题栏
- 用户头像与昵称区块
- 统计数字区域(关注 / 粉丝 / 获赞)
- 简介文本
- 操作按钮(发消息、关注)
- 主要内容列表
这六层结构,每一层在垂直方向上的对齐方式、间距、是否可扩展,都不一样。有的需要居中,有的需要左对齐,有的需要占满剩余空间。把它们组合在一个页面里,用到的正是 Column 的各种属性组合。
所以这篇文章不会只讲 Column 是什么,而是从真实拆解出发,把每个属性的选择逻辑讲清楚。
Column( children: [ _buildHeader(), // 顶部标题栏 _buildUserInfo(), // 头像昵称区块 _buildStats(), // 统计数字区域 _buildBio(), // 简介文本 _buildActionButtons(), // 操作按钮 _buildMainList(), // 主要内容列表 ], )这段代码看起来简单,但如果你把它直接跑在 OpenHarmony 设备上,大概率会遇到几个问题:统计数字区域在窄屏上挤压变形、操作按钮在软键盘弹出后被顶出屏幕、主要内容列表在高度不足时直接溢出。这些问题的根因,都出在 Column 的属性使用上。
2. Column 核心属性详解:对齐、排列与尺寸分配的底层逻辑
2.1 mainAxisAlignment 与 crossAxisAlignment:两条轴怎么控制
Column 的布局逻辑核心是两条轴:主轴和交叉轴。在 Column 中,主轴方向是垂直的,交叉轴方向是水平的。这两个轴的理解如果不透彻,后面的属性都是白搭。
我习惯把 Column 想象成一个垂直摆放的容器,里面的每个子组件都按照先后顺序从顶部往下排。主轴方向上的排列方式,由mainAxisAlignment决定;交叉轴方向上的对齐方式,由crossAxisAlignment决定。
Column( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Text('顶部'), Container(height: 100, color: Colors.blue), Text('底部'), ], )这段代码的效果是:三个子组件在垂直方向上分别靠容器顶部和底部排列,中间留有空白;同时每个子组件在水平方向上被拉伸到容器的最大宽度。CrossAxisAlignment.stretch是这个属性中最容易出问题的一个,它在 OpenHarmony 的屏宽差异下表现特别明显,平板和手机上的拉伸效果并不完全一致。
关于mainAxisAlignment的五个值,实际操作中的记忆方法:
start:从顶部开始堆叠end:全部靠底部堆叠center:垂直居中堆叠spaceBetween:首尾贴边,中间均分空隙spaceAround/spaceEvenly:所有空隙均分,区别在于边缘空隙的大小
其中spaceBetween在固定高度场景下非常好用,比如按钮栏左右各一个按钮时,用 Row 加spaceBetween比手动算间距省事多了。但注意:如果 Column 的高度是mainAxisSize.min,spaceBetween等于没有任何效果,因为容器高度只有子组件总高度,没有多余空隙可分。
2.2 mainAxisSize:为什么很容易被忽视
mainAxisSize是 Column 中最容易被忽视、却最能影响布局结果的属性。它的作用是决定 Column 自身占用主轴方向上的大小,只有两个值:
max:尽可能占满主轴方向所有可用空间min:只占子组件实际需要的总高度
很多刚接触 Flutter 的开发者会默认 Column 的高度就是子组件的总高度,这是错误的。默认情况下,mainAxisSize的值是max,也就是说,只要父容器给了足够的约束,Column 会一直拉伸到占满整个垂直空间。
Container( height: 400, child: Column( mainAxisSize: MainAxisSize.min, children: [Text('内容'), Text('内容')], ), )在这个例子中,mainAxisSize.min会让 Column 的高度刚好是两行文本的总高度,外层 Container 剩余的空白不会被子组件感知。如果你用的是默认的mainAxisSize.max,Column 会顶满 400 的高度,此时如果子组件没有占满空间,再配合mainAxisAlignment.spaceBetween,子组件就会被拉伸到各个边缘,效果完全不同。
实际案例:我在模拟项目里写一个页面底部固定操作栏时,用 Column 包裹两个按钮。如果 Column 直接用默认的max,按钮会被拉伸到贴近页面底部;如果希望按钮悬浮在页面中部区域,就必须明确把mainAxisSize设为min,再配合外部间距控制。
2.3 Expanded / Flexible / Spacer:在 Column 里分配空间的三种工具
这三种组件是 Column 布局中最核心的弹性工具。
Expanded的作用是让子组件占满剩余的主轴空间。它适合的场景是:页面有一个固定底部,中间区域需要自适应填满。比如一个聊天页面,消息列表占剩余空间,输入框固定在底部:
Column( children: [ Expanded( child: ListView.builder(...), // 消息列表 ), _inputBar(), // 底部输入框 ], )Flexible和Expanded的区别在于,Flexible允许子组件在未占满空间时不强制拉伸,它有fit参数,默认是FlexFit.loose。也就是说,子组件可以保持自身大小,剩余空间留白;而Expanded的fit是FlexFit.tight,强制占满。
Spacer是Expanded的一个简化封装,用来在子组件之间插入弹性空白,实现自适应间距。它特别适合需要“留白呼吸”的场景。
Column( children: [ Text('顶部信息'), Spacer(flex: 1), Text('中部信息'), Spacer(flex: 2), Text('底部信息'), ], )这里flex: 2的 Spacer 占用的间距是flex: 1的两倍。如果你希望两个区块之间间距比为 1:2,用 Spacer 比写死高度更稳妥,尤其是在不同屏幕高度下。
2.4 textDirection 与 verticalDirection:两个容易被忽略的属性
textDirection控制交叉轴方向上子组件的排列起点,默认是TextDirection.ltr,也就是从左往右排列。如果在某些特殊场景下你需要从右往左排列子组件,可以设置为TextDirection.rtl。这个属性在 Column 中主要影响的是crossAxisAlignment.start和end的基准方向。
verticalDirection控制主轴方向上子组件的排列顺序,默认是VerticalDirection.down。如果你设置为VerticalDirection.up,子组件会从底部往上排列。这个属性最容易踩坑的地方是:当你配合mainAxisAlignment使用时,排列起点会反转,导致代码逻辑看起来和预期不符。
Column( verticalDirection: VerticalDirection.up, children: [Text('A'), Text('B')], )这段代码会从底部开始先排列 A,再往上排列 B,视觉上 B 在 A 上面。如果把顺序理解反了,页面元素就会完全颠倒。在 OpenHarmony 设备上测试时,建议先初始化好这两个属性,不要在后期随意改动,否则排查布局问题时会增加干扰项。
提示:
textDirection和verticalDirection在绝大多数业务页面用不到默认值就够了。但如果你做的是横竖屏适配或国际化版本,这两个属性会成为必须考虑的因素。
3. 实战案例:从需求到代码的三个 Column 布局落地
3.1 案例一:个人中心页的垂直信息展示
个人中心页是 Column 最典型的应用场景。我的模拟项目里有一个页面,需求是这样:
- 头像区域居中,垂直方向上有 24 的顶部间距
- 昵称在头像下方,居中显示
- 统计数据(关注 / 粉丝 / 获赞)水平排列,占据页面 60% 宽度居中的位置
- 简介文本最多三行,超过省略
- 操作按钮横排两个,固定在页面底部
这个需求的布局结构,直接用 Column 从外到内嵌套即可:
Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ SizedBox(height: 24), _buildAvatar(), // 头像 80x80 圆形 SizedBox(height: 12), Text('昵称', style: ...), SizedBox(height: 16), _buildStatsRow(), // 统计区域,内部用 Row Padding( padding: EdgeInsets.symmetric(horizontal: 16), child: Text('简介简介简介...', maxLines: 3, overflow: TextOverflow.ellipsis), ), Spacer(), _buildActionButtons(), // 固定在底部 ], )这里有几个设计细节值得说明:
crossAxisAlignment设为center,让整个 Column 的子组件在水平方向上居中。但有一个例外:简介文本需要左对齐,而且顶部有较大边距,所以在 Text 外包了一层Padding,并用水平方向 padding 控制边距。这里有人会疑惑:crossAxisAlignment.center不会覆盖 Padding 吗?不会,Padding 只是给 Text 增加了内边距,Text 本身在交叉轴上的对齐仍然受 Column 的center控制,所以整体居中,文字在容器内部左对齐。操作按钮固定在底部,用的是
Spacer()。它把上方剩余空间全部顶开,让按钮始终贴底。这是最稳妥的方案,比mainAxisAlignment: spaceBetween更可预期,因为 Spacer 不会影响其他子组件的排列相对关系。统计区域是水平方向的三个数字 + 标题,必须用 Row 内部实现,Column 只负责把它作为一个整体块来排列。
这个页面在 OpenHarmony 平板和手机上的表现都很稳定。唯一的差异点是头像大小,我在不同设备上用了不同的屏幕适配方案,这个到第 5 节再展开。
3.2 案例二:表单页的间距与按钮固定
表单页是 Column 布局中另一个高频场景。表单页的特点:
- 多个输入框垂直排列
- 输入框之间需要固定间距
- 底部有个提交按钮,不能被键盘顶飞
- 键盘弹出时,页面不能整体溢出
我在模拟项目里写过一个登录表单页,结构是这样的:
Column( children: [ Expanded( child: SingleChildScrollView( child: Column( children: [ _buildTitle(), SizedBox(height: 32), _buildAccountInput(), SizedBox(height: 16), _buildPasswordInput(), SizedBox(height: 16), _buildCaptchaInput(), ], ), ), ), _buildSubmitButton(), ], )这个结构的关键在于:外层 Column 的高度是屏幕高度,里面的Expanded占满剩余空间,内部再用SingleChildScrollView包裹真正的表单内容,底部按钮固定不动。
如果不加Expanded和SingleChildScrollView,键盘弹出时表单会被顶出屏幕,或者按钮被键盘盖住,这在 OpenHarmony 设备上尤其明显。原因在于 OpenHarmony 应用默认的键盘避让逻辑和 Flutter 的resizeToAvoidBottomInset机制相互配合时,直接摆放的固定按钮会因为视口缩小而溢出。
我踩过的一次坑:最初版本把提交按钮直接放在 Column 的底部,没包SingleChildScrollView。在手机屏上键盘弹出后,Column 高度被压缩,按钮和输入框之间产生了 RenderFlex overflowed 报错。后来改成现在这个结构,问题彻底解决。
另外表单页的间距控制,我推荐用SizedBox写死间距,不要用 Spacer。因为表单页的布局要的是稳定一致的间距,而不是弹性留白。弹性留白会导致不同设备上的输入框间距差异大,视觉不统一。
3.3 案例三:动态列表卡片与加载状态布局
动态列表页是 Column 与滚动容器结合最紧密的场景。这里的关键是:加载状态、错误状态、空状态,都应该独立出来,用 Column 居中展示。
我的实现思路:
Widget buildBody() { if (_isLoading) { return _buildLoadingState(); } if (_hasError) { return _buildErrorState(); } if (_listData.isEmpty) { return _buildEmptyState(); } return _buildListView(); } Widget _buildLoadingState() { return Column( mainAxisAlignment: MainAxisAlignment.center, children: [CircularProgressIndicator(), SizedBox(height: 16), Text('加载中...')], ); }_buildLoadingState里的 Column 用mainAxisAlignment.center让加载图标垂直居中。但注意一个细节:这个 Column 必须放在一个有明确高度约束的容器里,否则它在页面中只会占自身高度,无法实现居中。实际代码中我是在SizedBox.expand里放 Column,或者把外层结构设计成 Column + Expanded 包裹:
Column( children: [ Expanded( child: _buildBody(), ), ], )空状态和错误状态同理,它们本质上都是垂直居中的一组内容。这种设计让页面不同状态之间的切换非常干净,不会影响底部固定动作栏。
4. 踩过的坑:Column 溢出、嵌套与适配问题排查全过程
4.1 现象与日志:RenderFlex overflowed 第一次出现
我的模拟项目跑到 OpenHarmony 平板上时,第一次遇到了 RenderFlex overflowed 报错。屏幕下方出现一个黄黑相间的条纹,控制台里打出了大量警告日志:
RenderFlex overflowed by 32 pixels on the bottom.这个现象的直观含义是:Column 内所有子组件的高度总和,超出了 Column 可用的最大高度 32 像素。问题发生在一个内容详情页,页面结构是:
Column( children: [ _buildHeader(), Expanded( child: _buildContent(), ), _buildFooter(), ], )按理说这个结构不会溢出,因为中间有 Expanded 吸收剩余空间。但日志里明确提示是 Column 底部溢出。为什么?
根因在_buildContent()内部。这个方法的返回值是一个 Column,而且这个 Column 内部没有使用 Expanded 或 Flexible,而是直接放了多个文本和图片组件:
Widget _buildContent() { return Column( children: [ Text('标题'), SizedBox(height: 8), Image.network(...), SizedBox(height: 8), Text('正文内容...'), SizedBox(height: 8), Text('更多内容...'), ], ); }问题链条是这样的:Expanded给了_buildContent一个确定的高度约束,例如 400 像素。但_buildContent返回的 Column 使用的是mainAxisSize.max,它默认要占满这 400 像素;可内部的子组件总高度在实际运行时是 432 像素。结果就是 Column 内部溢出。
这里有个陷阱:即便外部已经有 Expanded 约束高度,内部 Column 依然需要自己处理内容超出问题。最直接的修复方案是让内部内容可以滚动,或者用 Flexible 包裹可伸缩区域。
4.2 根因定位:是宽度约束还是高度约束
排查 RenderFlex overflow 的第一步,就是分清是哪个方向溢出。Column 的溢出通常显示在底部,但如果你看到的是 horizontal 方向的溢出,那问题其实出在 Column 的交叉轴上。
比如:
RenderFlex overflowed by 21 pixels on the right.这说明 Column 内部某个子组件在水平方向上超出了 Column 的最大宽度。常见原因有:
- 文本过长且没有设置
maxLines或overflow - 图片没有设置
fit属性,使用原始尺寸超出了约束 - Row 子组件总和超过 Column 的交叉轴宽度
我遇到的一个实际案例是:在 Column 里放了一个 Row,Row 里面有三个文本组件,其中一个文本内容在平板宽字体设置下特别长,把整个 Row 撑到了 Column 边界右侧,导致交叉轴溢出。修复方法是给那个文本加上Expanded或Flexible包裹,让它自动省略多余部分。
关于文本溢出的处理,有一个通用经验:只要是动态文本,尽量都加上overflow: TextOverflow.ellipsis和maxLines,避免文本成为布局溢出的源头。
4.3 一个完整排查链路示例
为了让你更直观地理解排查过程,我记录一次实际排错:
第一步,从日志中看到溢出信息,地址定位在_buildContent中第 3 个子组件的位置。这基本锁定是标题下方的图片区域出了问题。
第二步,检查图片。图片是网络图,没有设定宽高,也没有fit属性。在模拟器上它显示正常,因为模拟器屏宽和图片宽度接近;到了 OpenHarmony 平板,屏宽更宽,但图片仍然是原图尺寸,于是水平方向超出了 Column 的最大宽度约束,导致交叉轴溢出。
第三步,修复。给图片外层加一个AspectRatio或者SizedBox包裹,让图片宽高比适配容器:
ClipRRect( borderRadius: BorderRadius.circular(8), child: Image.network( url, width: double.infinity, fit: BoxFit.cover, ), )这样图片宽度铺满 Column 可用宽度,高度按比例自适应,不会溢出。同时为了高度可控,我用AspectRatio强制了 16:9 的比例:
AspectRatio( aspectRatio: 16 / 9, child: Image.network(url, fit: BoxFit.cover), )第四步,验证。平板和手机屏上都跑一遍,不再出现溢出条纹。
整个排查链路的关键在于:不要被日志里的 first affected line 迷惑,要同时考虑主轴和交叉轴两个方向上的约束。图片、文本、Row 是交叉轴溢出的三大源头,需要优先检查。
4.4 修复方案的对比与选择
对于 Column 内容溢出,常见的修复方案有三种,区别如下:
| 方案 | 适用场景 | 风险 |
|---|---|---|
| 外层包 SingleChildScrollView | 内容整体高度不固定,需要滚动 | 会改变滚动行为,不能配合 Expanded 使用 |
| 用 Flexible 替代部分子组件 | 有明确的弹性区域 | 需要合理分配 flex 比例,否则布局比例失真 |
| 固定子组件高度与比例 | 内容尺寸可控 | 需要处理不同屏幕的适配,维护成本略高 |
我的选择原则:
- 如果页面本身就是列表类,直接使用 ListView,不要用 Column 套 SingleChildScrollView
- 如果页面是固定区块 + 可变内容,用 Flexible 包可变内容
- 如果溢出来自单个子组件(如图片、长文本),优先单独修复该子组件,而不是整体换容器
在这套经验下,我后来写 Column 时养成了习惯:每个子组件尽量洁身自好,注意自身在交叉轴上的宽度上限,而不是全指望父级容器兜底。这样一来,即使某个子组件变化,也不会拖垮整个页面布局。
5. 让 Column 布局更稳的工程细节:适配、性能与维护
5.1 屏幕适配:不同设备密度下的 Column
OpenHarmony 覆盖的设备形态比安卓更杂,手机、平板、带屏设备,屏幕密度各不相同。我在模拟项目里发现,Column 布局在不同设备上的差异主要体现为两点:边距与间距,内容密度带来的视觉散乱。
我看到的常用方案是按设计稿比例换算。比如设计稿基准宽度 360dp,某设备实际宽度是 720dp,那么间距 = 设计稿间距 * (720 / 360) = 2 倍。写成一个动态函数:
double rw(double size) { return size * MediaQuery.of(context).size.width / 360; }然后用这个函数替换布局里的写死尺寸:
Column( children: [ SizedBox(height: rw(24)), Text('标题', style: TextStyle(fontSize: rw(16))), ], )这个方案在 OpenHarmony 上的适应性比较好,因为 Flutter 的 MediaQuery 能直接拿到设备逻辑宽,换算过程不涉及底层 API 差异。唯一的不足是,极宽屏设备(平板)下,间距会被放大得过多,视觉上失去紧凑感。所以在平板场景,我会做一次上限截断,比如间距最大不超过 32:
double rw(double size) { final scale = MediaQuery.of(context).size.width / 360; return math.min(size * scale, size * 1.5); }5.2 布局代码的可维护性:拆 Widget 而不是堆嵌套
Column 本身结构简单,但当页面复杂后,如果所有内容都堆在一个Column(children: [...])里,代码会迅速变成一团乱麻。我在模拟项目里为了让 Column 布局可维护,遵循一条原则:一个 Column 的 children 不超过 6 个。
如果超过 6 个,就把部分子组件拆成独立的 Widget 方法或类。这样做的好处很明显:
- 每个区块可以单独复用和测试
- 问题定位更快,可以直接跳到某个区块的方法查看
- 后续增删区块不会影响上层 Column 的结构
比如个人中心页,我会拆成_buildUserCard()、_buildStatsArea()、_buildActionBar()、_buildListArea()四个方法,然后在 Column 里只放四个方法调用。代码阅读体验好很多,也方便调试。
5.3 性能观察:Column 本身的开销与避免重复布局
Column 本身是个轻量级布局组件,不需要担心它的性能。真正容易在 OpenHarmony 设备上暴露性能问题的是布局重建频率。
在 Flutter 中,如果你在 Column 的 children 里创建了内联函数方法,每次父组件 rebuild 时,这些 Widget 对象都会重建。Column 本身还好,但如果你在 Column 里放了一些比较重的子组件(比如图片、复杂文本),重建频率过高就会影响帧率。
我在模拟项目里做过一个测试:在 OpenHarmony 平板上,一个包含 8 个子组件的 Column,如果每次 build 都重新创建所有子组件,帧率在低端设备上会明显下降。改进方法是用const构造子组件:
Column( children: [ const _Header(), const _StatsArea(), _buildList(), // 只有列表需要动态重建 ], )const让 Flutter 在组件树 diff 时跳过这些子组件的重建,显著减少 layout 阶段开销。
另一个经验:不要滥用 Spacer 和 Expanded。每个 Spacer / Expanded 都会参与 flex 布局计算,当一个 Column 里有 5 个以上的 flex 子组件时,布局计算会变得更复杂,低端设备上的计算开销也会上升。能用固定间距就用 SizedBox,弹性区域控制在 2~3 个以内。
5.4 与单列滚动、状态重建的配合
Column 搭配 ListView 时的设计要特别小心。有些人会写出这样的结构:
Column( children: [ Expanded( child: ListView(...), ), _bottomBar(), ], )这是合理的。但不合理的是把 ListView 直接放在 Column 里,不加 Expanded:
Column( children: [ ListView(...), // 错误:ListView 在 Column 里没有高度约束 _bottomBar(), ], )这样写会让 ListView 尝试占据无限高度,最终导致布局错误。这个坑在 OpenHarmony 设备上的表现和安卓一致,但初学者容易忽略。
另外,Column 内部如果依赖外部状态,状态重建时要注意避免整个 Column 重排。我的做法是:把动态内容隔离到子 Widget 里,让外层 Column 保持相对稳定,只让需要变化的子区块重建。这样即使状态频繁变化,Column 主体布局也不会频繁重新计算。
6. 最后的工程建议:我用 Column 时的一点点心得
基于这段 OpenHarmony 迁移经历,我想总结几条直接可用的建议:
- Column 的默认
mainAxisSize是max,写任何页面之前先想清楚你希望它占满还是收缩,不要留到报错再去排查。 - 溢出问题不要只盯着主轴看,交叉轴溢出(图片、文本、Row 超出宽度)在 OpenHarmony 多尺寸设备上出现的频率更高。
- 表单页用 Expanded + SingleChildScrollView 包住输入区,把操作按钮单独放在 Column 底部,键盘弹出才不会乱。
- 动态文本一律加
maxLines和overflow,作为团队规范来推行,能从源头减少大量 Column 溢出场景。 - 能用 const 约束子组件就用,OpenHarmony 低端设备上性能收益非常明显。
有一次和一个同样在迁移项目的朋友聊天,他说自己调了两天 Column 布局都没搞定,最后发现只是某个 Text 少了maxLines。听他讲完,我挺有感触:布局问题绕来绕去,最后都是基础属性理解得不够扎实。Column 是 Flutter 布局中最基础的组件之一,却决定了页面的底层体验。把它的每个属性放在真实设备上验证一遍,比刷多少文档都管用。
如果你最近也在 OpenHarmony 上用 Flutter 写页面,希望这篇内容能帮你少走几步弯路。