(八)线性布局 Row&Column
线性布局也就是子部件沿水平或者垂直方向排列。在Flutter中线性布局是通过Row和Column来实现的;这类似于Android的LinearLayout的控件;而Row和Column都继承自Flex(弹性布局);
主轴和纵轴
对于线性布局而言,是由主轴和纵轴之分的;
- 如果布局是沿
水平方向,那么主轴就是指水平方向,纵轴就是垂直方向; - 如果布局是沿
垂直方向,那么主轴就是指垂直方向,纵轴就是水平方向; MainAxisAlignment主轴对齐;CrossAxisAlignment纵轴对齐;
准备工作
在之前的学习中,我们已经知道了Container不见会根据其内部的子部件改变自身大小,比如:
一个默认的满屏的黄色背景的Container,如果我们在其内部添加一个子部件Text:
原来满屏的黄色背景的Container变成了Text部件一样的大小;
接下来我们再来看一个Container的属性:alignment对齐方式,其定义如下:
final AlignmentGeometry? alignment;
aligment需要一个AlignmentGeometry类型的值,表示子部件在父部件中的起始位置。AlignmentGeometry是一个抽象类,它有两个常用的子类:Alignment和FractionOffset;
这里我们先使用Alignment来进行布局,其构造函数为:
const Alignment(this.x, this.y)
x,y取值范围为-1到1;中心点是 (0,0)
Container被拉大,而Text放在了Container的中心点上;
那么,接下来,我们来分析一下Row的布局方式;
Row
Row可以沿水平方向布局其子Widget;其定义如下:
Row({
Key? key,
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
MainAxisSize mainAxisSize = MainAxisSize.max,
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
TextDirection? textDirection,
VerticalDirection verticalDirection = VerticalDirection.down,
TextBaseline? textBaseline, // NO DEFAULT: we don't know what the text's baseline should be
List<Widget> children = const <Widget>[],
})
textDirection:表示水平方向子部件的布局顺序是从左到右还是从右到左;默认为系统当前环境的文本方向:中文,英文为从左到右,阿拉伯语为从右到左;mainAxisSize:表示Row在主轴方向也就是水平方向上占用的控件;MainAxisSize.max(默认):意思是尽可能多的占用水平方向的空间;此时不管子部件在水平方向上实际占用多少空间,Row的宽度始终都是水平方向的最大宽度;MainAxisSize.min:表示尽可能少的占用水平方向的空间;如果子部件没有沾满水平方向剩余空间,那么Row的世纪宽度就是所有子部件占用水平空间之和;
mainAxisAlignment:表示子部件在Row所占用的水平空间内的对齐方式:mainAxisSize值为MainAxisSize.min时,mainAxisAlignment无意义,此时子部件的总宽度与Row的宽度一样;mainAxisSize值为MainAxisSize.max(默认) 时:MainAxisAlignment.start表示沿textDirection的初始化方向对齐TextDirection.ltr:MainAxisAlignment.start表示左对齐;TextDirection.rtl:MainAxisAlignment.start表示右对齐;
MainAxisAlignment.end与MainAxisAlignment.start表示的初始化对齐方向时相反的;MainAxisAlignment.center表示居中对齐;
- 可以理解为:
textDirection是mainAxisAlignment的参考系;
verticalDirection:表示Row纵轴 (垂直) 的对齐方向;VerticalDirection.down:表示从上到下;VerticalDirection.up:表示从下到上;
crossAxisAlignment:表示子部件在纵轴方向上的对齐方式;Row的高度等于子部件中最高的子元素的高度;其取之和MainAxisAlignment一样包含start,end和center三个值;不同的是其参考系是verticalDirection:verticalDirection值为VerticalDirection.down时,CrossAxisAlignment.start表示顶部对齐;verticalDirection值为VerticalDirection.up时,CrossAxisAlignment.start表示底部对齐;CrossAxisAlignment.end和CrossAxisAlignment.start相反;
children子部件数组;
我们现在先在Row中添加三个Text,看一下默认效果:
默认三个Text为居左对齐;红色线框区域为Row的区域,两条蓝色线交叉点为Row的中心点; 因为Row是横向的,所以此时Alignment的x的值对Row的布局是没有影响的: 
同样的
y值对Column的布局也是没有影响的;
接下来我们将Row的textDirection设置为TextDirection.rtl看一下运行效果:
三个Text的初始化顺序变为从右开始; 为了便于查看效果,我们将多个Row放在界面中,从上到下排列,效果如图:

- 第一行:默认居中对齐;
- 第二行:由于设置了
mainAxisSize的值为MainAxisSize.min,所以Row的对齐方式mainAxisAlignment就没有了意义,子部件会从左到右布局显示,子部件的宽度之和与Row的宽度一致; - 第三行:由于将
textDirection设置为TextDirection.rtl,表示子部件将会从右到左的初始化顺序进行布局,而此时MainAxisAlignment.end表示的是左对齐; - 第四行:由于多个
Text的字体大小不一致,所以其高度也不一样;而VerticalDirection.up表示从下到上的顺序排列,而此时CrossAxisAlignment.start表示在纵轴上底部对齐; - 第五行:
CrossAxisAlignment.start默认表示顶部对齐;
Column
Column可以在垂直方向上布局其子部件,参数和Row是一样的,不同的是Column布局方向为垂直,主轴和纵轴与Row正好相反;
比如,我们将之前布局中的Row直接修改为Column来看一下效果: 
本来
Row中从左到右布局的三个Text,换成Column之后变为了从上到下布局,并且因为Alignment的x为-1,所以在在水平方向上,先是在了屏幕的最左侧;
关于 MainAxisAlignment 的补充
MainAxisAlignment是一个枚举类型,其定义如下:
enum MainAxisAlignment {
start,
end,
center,
spaceBetween,
spaceAround,
spaceEvenly,
}
我们发现MainAxisAlignment除了start,end和center三个之和,还有spaceBetween,spaceAround和spaceEvenly三个值,那么这三个值的效果是什么样子的呢?
spaceBetween
spaceBetween意思是:所有的子部件布局完成之后,剩下的空间平均分布到几个子部件之间;
演示效果如下: 
spaceAround
spaceAround意思是:所有的子部件布局完成之后,剩下的空间平均分布到几个子部件周围;
为了更好的演示效果,我们此处改变字体大小之后看效果如下:

spaceEvenly
spaceEvenly意思是:所有的子部件布局完成之后,剩下的空间和子部件一起平均分; 
图中粉红色横线表示的间隔距离相等;
关于 CrossAxisAlignment 的补充
除了我们常用的枚举值之外,CrossAxisAlignment还有baseline的枚举值,那么效果如何呢?
将值改为baseline之后,工程直接报错,这是因为baseline这个枚举值要结合textBaseline属性进行使用;效果如下: 
最终效果:三个
Text部件虽然没有对齐,但是其中的文字底部对齐了;
关于 Expanded 的补充
Expandeed是一个自适应部件;我们简单看一下效果:
使用Expanded部件把Text包起来之后,Text部件文字超过限制之后,可以自己换行显示了;
我们继续修改代码:
我们把Text包括在Container里边,此时发现Container也自适应的在主轴方向上进行了拉伸;
许哟啊注意的是
Expanded所在的children数组不可以使用const修饰;
此时,我们修改Container的高度:
高度生效了;
- 在
Row中,给Expanded的子部件设置高度有意义,宽度无意义 - 在
Column中,给Expanded的子部件设置高度无意义,宽度有意义;
Expanded在主轴方向上不会留下间隙,将被Expanded拉伸;
