3. 布局基础
布局,说白了就是决定控件「站哪儿」的问题。
我刚入行那会儿,觉得布局很简单——拖几个控件到界面上不就完了?结果一到跨平台,Android 上好好的,iOS 上跑飞了。嗯,从那以后我才认真研究起布局的底层逻辑。
绝对定位:最直接,也最脆弱
绝对定位就是给控件一个固定的 x、y 坐标。比如在 Qt 里写:
button.setGeometry(100, 50, 120, 40)
这行代码的意思是:按钮左上角在 (100, 50),宽 120,高 40。
听起来很直观对吧?但我在项目中吃过它的亏。有一次做嵌入式界面,屏幕分辨率从 800x480 换到 1024x600,所有控件全错位了。改坐标改到怀疑人生。
- 原型快速验证
- 固定尺寸的嵌入式屏幕
- 游戏中的 HUD 元素
相对布局:让控件「互相商量」
相对布局的核心思想是:控件的位置是相对于其他控件或父容器来定的。
你想想看,如果我说「确定按钮在取消按钮右边 10 像素」,而不是「确定按钮在 (300, 200)」,是不是灵活多了?
在 Android 里,RelativeLayout 是这样用的:
<Button
android:id="@+id/btn_ok"
android:layout_toRightOf="@id/btn_cancel"
android:layout_marginLeft="10dp" />
我个人习惯把相对布局用在表单里。比如「标签在输入框左边」、「错误提示在输入框下方」。这样不管屏幕怎么变,它们的关系始终不乱。
水平布局与垂直布局:最常用的「排列工具」
这两个布局说白了就是「排排坐」。水平布局让控件从左到右排,垂直布局让控件从上到下排。
在 Flutter 里,水平布局用 Row,垂直布局用 Column:
Row(
children: [
Icon(Icons.star),
Text('评分 4.8'),
Spacer(),
Text('¥ 29.9'),
],
)
你看,一行代码就把三个控件排好了。而且 Spacer 会自动把剩余空间吃掉,让价格跑到右边去。
我建议你记住一个原则:能用 Row/Column 解决的问题,就别用绝对定位。我在做跨平台项目时,90% 的布局需求靠这两个就能搞定。
| 布局类型 | 适用场景 | 常见坑点 |
|---|---|---|
| 水平布局 | 导航栏、标签页、按钮组 | 控件过多时溢出 |
| 垂直布局 | 列表、表单、文章内容 | 高度不够时滚动 |
网格布局:二维空间的「排兵布阵」
网格布局把界面分成行和列,每个控件占据一个或多个格子。它特别适合做计算器、相册、仪表盘这类规整的界面。
在 Qt 里,QGridLayout 是这样用的:
layout = QGridLayout()
layout.addWidget(button_1, 0, 0) # 第0行第0列
layout.addWidget(button_2, 0, 1) # 第0行第1列
layout.addWidget(button_3, 1, 0, 1, 2) # 第1行,跨2列
为什么会用到「跨列」?你想想计算器上的「0」按钮,它通常比别的按钮宽一倍。网格布局处理这种需求就特别优雅。
表单布局:专为「标签+输入框」而生
表单布局是垂直布局的「专业版」。它自动把标签和输入框对齐,而且支持「必填标记」、「错误提示」等常见需求。
在 Qt 里,QFormLayout 用起来很简洁:
form = QFormLayout()
form.addRow('用户名:', username_input)
form.addRow('密码:', password_input)
form.addRow('', submit_button)
你看,左边是标签,右边是输入框,自动对齐。最后一行留空标签,让提交按钮独占一行。
我个人习惯在表单布局里加一个「必填项」的视觉提示。比如在标签前加红色星号,或者在输入框边框变红。用户一看就明白,不用多解释。
知识体系总览
下面这张图帮你理清这五种布局的关系和选择逻辑:
这张图的核心逻辑是:先问自己「屏幕尺寸固定吗?」——固定就用绝对定位,不固定就往下走。再问「控件之间有相对关系吗?」——有就用相对布局,没有就看排列方式。一维排列用水平/垂直,二维网格用网格布局,标签+输入框用表单布局。
好了,布局基础就聊到这儿。这些知识够你应付 80% 的跨平台布局场景了。剩下的 20%,靠的是经验积累和踩坑——嗯,我也还在继续踩。