Flutter 常用线性布局的使用小总结

115 阅读3分钟

安卓原生和网页的 UI 结构都更像是平面描述的,层级关系不是很明显,可以写的比较扁平。然而在 Flutter 里面,由于一切皆 Widget 的思想, UI 就成了天然的树形结构,从最开始的 MaterialApp 组件开始,逐步分支,分别深入,层层嵌套。整个过程是由外向内,从框架到细节进行填充的。

这个思路其实很符合我们的思维方式,先搭一个大概的架子,然后再完善细节。所以写的时候最好也根据层级关系来,先把页面的结构写清楚,划分成不同的部分,再分别完成。每次划分就是抽离拆分的好时机,避免嵌套过深影响阅读,也方便子项组件复用。

简介

常用的线性布局有:Row,Colum。此外还有一个很相似的 Wrap,自动换行的弹性布局。如果子组件们在一横排中就用 Row 行布局,如果是在一个竖排当中,那就用 Column 列布局。如果想要在一个方向上铺满之后自动换行,那就用 Wrap 包裹布局。他们只用来提供布局,自身不会被渲染出来。

这些布局一般会默认在主方向(子组件排列方向)上自动占满所有空间,行列布局可以设置为最小尺寸,以提供把一堆组件包裹成一个从而方便处理的效果。与主方向垂直的是副方向,各种属性以 Cross 开头,默认子组件在副方向上居中。两个方向上的对齐都有着丰富的选择:紧贴首尾,居中,不同方式的均分等。

常用场景

一个典型的效果:左边图标,右边是长度不固定的一堆文字。即一个固定大小的子组件,加上一个填满剩余部分的子组件。需要填满剩余部分的子组件用 Expanded 包起来即可。

如果是左右两边各紧贴一个组件,中间都要空下来,可以使用 Spacer 组件,它的作用就是占满主方向剩余的位置。用这个组件可以手动实现各个对齐方式。视情况选用更方便的即可。

此外还有一个常见的问题,Text 组件在布局里长度溢出。最方便的办法是放在一个 Container 里面,或者如果在线性布局中,也可以用 Extanded 包裹。或者给文字设置 Overflow 属性,抹去超出长度的部分。

显著特征和典型问题

线性布局在 Flutter 中的显著特征有三个:

  1. 多子组件,一般默认会占满主方向剩余空间;
  2. 在一个主方向上可以无限拓展,但不能包含主方向长度未知的组件;
  3. 主方向长度不是无限时,放在滑动组件中如超出屏幕尺寸就可以被滑动;

其中 2 和 3 涉及到使用中最典型的问题:

一个是 无限套未知。线性布局中如果出现主方向长度未知的组件(例如 PageView,高度不确定,取决于其子组件),则必须使用 Expanded 或有固定值的 SizedBox 将其包裹,给它一个确定的长度。否则就会因为尺寸无法向下传递而布局崩溃。

一个是 滑动套无限。如果一个 Column 自身已经套了 SingleChildScrollView 等组件,高度超出屏幕后可以滚动了,那么此时它的子组件就必须有一个确定的高度。所有 Expanded 或类似效果的都不可行。因为滚动的位置本身是需要通过内容的总高度来计算的,如果内容中有一项无限高,那么就会无法计算,导致布局崩溃。

PS. 这里要区分清楚和无限列表的区别,无限列表是内容的个数无限,可以一直在滑动末尾懒加载新的内容或进行循环,而不是内容的高度无限哈。