所谓线性布局,即指沿水平或垂直方向排布子组件。Flutter中通过Row和Column来实现线性布局,类似于Android中的LinearLayout控件。Row和Column都继承自Flex,我们将在弹性布局一节中详细介绍Flex。
主轴和纵轴
对于线性布局,有主轴和纵轴之分,如果布局是沿水平方向,那么主轴就是指水平方向,而纵轴即垂直方向;如果布局沿垂直方向,那么主轴就是指垂直方向,而纵轴就是水平方向。在线性布局中,有两个定义对齐方式的枚举类MainAxisAlignment和CrossAxisAlignment,分别代表主轴对齐和纵轴对齐。
Row
https://api.flutter.dev/flutter/widgets/Row-class.html
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 = TextBaseline.alphabetic,List<Widget> children = const <Widget>[],})
textDirection:主轴的布局方向,默认为系统当前Locale环境的文本方向(如中文、英语都是从左往右,而阿拉伯语是从右往左)。- ltr:从左到右。
- rtl:从右到左。
mainAxisAlignment:主轴的对齐方式,默认为MainAxisAlignment.start。注意:如果mainAxisSize值为MainAxisSize.min,则此属性无意义,因为子组件的宽度等于Row的宽度。只有当mainAxisSize的值为MainAxisSize.max时,此属性才有意义。mainAxisAlignment 的参考系是textDirection。- start:左对齐。如
textDirection取值为TextDirection.ltr时,则MainAxisAlignment.start表示左对齐,textDirection取值为TextDirection.rtl时表示从右对齐。 - center:居中对齐。
- end:右对齐。
- spaceBetween:两端对齐。项目之间的间隔相等,项目与边框的间隔为0。
- spaceAround:项目之间的间隔 相等,且是 项目与边框的间隔 的2倍。
- spaceEvenly:项目之间的间隔、项目与边框的间隔 全部相等。
- start:左对齐。如
verticalDirection:纵轴的布局方向,默认是VerticalDirection.down。- down: 从上往下。
- up :从下往上。(从底部开始,并垂直堆叠到顶部,对齐方式的 start 在底部,end 在顶部)
crossAxisAlignment:纵轴的对齐方式,默认为:CrossAxisAlignment.center。Row的高度等于子组件中最高的子元素高度,crossAxisAlignment的参考系是verticalDirection。- start:顶部对齐。
verticalDirection值为VerticalDirection.down时crossAxisAlignment.start指顶部对齐,verticalDirection值为VerticalDirection.up时,crossAxisAlignment.start指底部对齐。 - center:居中对齐。
- end:底部对齐。
- stretch:拉伸。
- baseline:基线对齐。
- start:顶部对齐。
mainAxisSize:在主轴方向占用的空间,默认是MainAxisSize.max。- max:表示尽可能多的占用水平方向的空间,此时无论子widgets实际占用多少水平空间,
Row的宽度始终等于水平方向的最大宽度; - min:表示尽可能少的占用水平空间,当子组件没有占满水平剩余空间,则
Row的实际宽度等于所有子组件占用的的水平空间;
- max:表示尽可能多的占用水平方向的空间,此时无论子widgets实际占用多少水平空间,
children:子组件数组。
主轴对齐方式:

spaceAround 和 spaceEvenly 区别是:
- spaceAround :第一个子控件距开始位置和最后一个子控件距结尾位置是其他子控件间距的一半。
- spaceEvenly : 所有间距一样。
次轴对齐方式:

示例:
class IconContainer extends StatelessWidget {double width;double height;double size;IconData icon;Color color;IconContainer({key,this.width = 50.0,this.height = 50.0,this.size = 32.0,@required this.icon,this.color = Colors.white,}) : super(key: key);@overridebuild(context) {return Container(width: width,height: width,color: Color(Base.getRandomColor()),child: Center(child: Icon(icon, size: size, color: color),),);}}
mainAxisSize

Container(height: 100,color: Colors.grey,child: Row(mainAxisAlignment: MainAxisAlignment.center,mainAxisSize: MainAxisSize.min, //如果为min, mainAxisAlignment也就没意义上了children: [IconContainer(icon: Icons.home, width: 40.0),IconContainer(icon: Icons.search),IconContainer(icon: Icons.arrow_back, width: 60.0),],),);
textDirection

Row(crossAxisAlignment: CrossAxisAlignment.start,mainAxisAlignment: MainAxisAlignment.start,textDirection: TextDirection.rtl,children: [IconContainer(icon: Icons.home, width: 40.0),IconContainer(icon: Icons.search),IconContainer(icon: Icons.arrow_back, width: 60.0),],),
verticalDirection

Row(crossAxisAlignment: CrossAxisAlignment.start,mainAxisAlignment: MainAxisAlignment.start,verticalDirection: VerticalDirection.up,children: [IconContainer(icon: Icons.home, width: 40.0),IconContainer(icon: Icons.search),IconContainer(icon: Icons.arrow_back, width: 60.0),],),
Column
Column可以在垂直方向排列其子组件。参数和Row一样,不同的是布局方向为垂直,主轴纵轴正好相反,可类比Row来理解。
实际上,Row和Column都只会在主轴方向占用尽可能大的空间,而纵轴的长度则取决于他们最大子元素的长度。如果我们想让里面控件在整个手机屏幕中间对齐,我们有两种方法:
将
Column的宽度指定为屏幕宽度;这很简单,我们可以通过ConstrainedBox或SizedBox来强制更改宽度限制,例如:Container(constraints: BoxConstraints(minWidth: double.infinity),color: Colors.grey,child: Column(// crossAxisAlignment: CrossAxisAlignment.center,mainAxisAlignment: MainAxisAlignment.center,children: [IconContainer(icon: Icons.home, width: 40.0),IconContainer(icon: Icons.search),IconContainer(icon: Icons.arrow_back, width: 60.0),],),);
将
minWidth设为double.infinity,可以使宽度占用尽可能多的空间。- 使用
CenterWidget;

特殊情况
如果Row里面嵌套Row,或者Column里面再嵌套Column,那么只有最外面的Row或Column会占用尽可能大的空间,里面Row或Column所占用的空间为实际大小,下面以Column为例说明:
Container(padding: EdgeInsets.all(16),color: Colors.grey,child: Column(mainAxisAlignment: MainAxisAlignment.start,mainAxisSize: MainAxisSize.max, //有效,外层Colum高度为整个屏幕children: [Container(color: Colors.green,child: Column(mainAxisSize: MainAxisSize.max, //无效,内层Colum高度为实际高度children: [IconContainer(icon: Icons.home, width: 40.0),IconContainer(icon: Icons.search),IconContainer(icon: Icons.arrow_back, width: 60.0),Text('hello'),],),),],),);

如果想让里面的Column占满外部的Column,可以使用 Expanded 组件:
Container(padding: EdgeInsets.all(16),color: Colors.grey,child: Column(mainAxisAlignment: MainAxisAlignment.start,mainAxisSize: MainAxisSize.max, //有效,外层Colum高度为整个屏幕children: [Expanded(child: Container(color: Colors.green,child: Column(mainAxisSize: MainAxisSize.max, //无效,内层Colum高度为实际高度children: [IconContainer(icon: Icons.home, width: 40.0),IconContainer(icon: Icons.search),IconContainer(icon: Icons.arrow_back, width: 60.0),Text('hello'),],),),),],),);

