所谓线性布局,即指沿水平或垂直方向排布子组件。Flutter中通过RowColumn来实现线性布局,类似于Android中的LinearLayout控件。RowColumn都继承自Flex,我们将在弹性布局一节中详细介绍Flex

主轴和纵轴

对于线性布局,有主轴和纵轴之分,如果布局是沿水平方向,那么主轴就是指水平方向,而纵轴即垂直方向;如果布局沿垂直方向,那么主轴就是指垂直方向,而纵轴就是水平方向。在线性布局中,有两个定义对齐方式的枚举类MainAxisAlignmentCrossAxisAlignment,分别代表主轴对齐和纵轴对齐。

Row

https://api.flutter.dev/flutter/widgets/Row-class.html
Row可以在水平方向排列其子widget。定义如下:

  1. Row({
  2. Key key,
  3. MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start, //主轴的排序方式
  4. MainAxisSize mainAxisSize = MainAxisSize.max, //主轴方向占用的空间
  5. CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center, //次轴的排序方式
  6. TextDirection textDirection, //主轴方向子组件排列顺序
  7. VerticalDirection verticalDirection = VerticalDirection.down, //次轴方向子组件的排列顺序
  8. TextBaseline textBaseline = TextBaseline.alphabetic,
  9. List<Widget> children = const <Widget>[],
  10. })
  • 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:项目之间的间隔、项目与边框的间隔 全部相等。
  • verticalDirection:纵轴的布局方向,默认是VerticalDirection.down
    • down: 从上往下。
    • up :从下往上。(从底部开始,并垂直堆叠到顶部,对齐方式的 start 在底部,end 在顶部)
  • crossAxisAlignment:纵轴的对齐方式,默认为:CrossAxisAlignment.center 。Row的高度等于子组件中最高的子元素高度,crossAxisAlignment的参考系是verticalDirection
    • start:顶部对齐。verticalDirection值为VerticalDirection.downcrossAxisAlignment.start指顶部对齐,verticalDirection值为VerticalDirection.up时,crossAxisAlignment.start指底部对齐。
    • center:居中对齐。
    • end:底部对齐。
    • stretch:拉伸。
    • baseline:基线对齐。
  • mainAxisSize:在主轴方向占用的空间,默认是MainAxisSize.max
    • max:表示尽可能多的占用水平方向的空间,此时无论子widgets实际占用多少水平空间,Row的宽度始终等于水平方向的最大宽度;
    • min:表示尽可能少的占用水平空间,当子组件没有占满水平剩余空间,则Row的实际宽度等于所有子组件占用的的水平空间;
  • children :子组件数组。

主轴对齐方式:

线性布局 Row、Column - 图1
spaceAround 和 spaceEvenly 区别是:

  • spaceAround :第一个子控件距开始位置和最后一个子控件距结尾位置是其他子控件间距的一半。
  • spaceEvenly : 所有间距一样。

次轴对齐方式:

线性布局 Row、Column - 图2

示例:
  1. class IconContainer extends StatelessWidget {
  2. double width;
  3. double height;
  4. double size;
  5. IconData icon;
  6. Color color;
  7. IconContainer({
  8. key,
  9. this.width = 50.0,
  10. this.height = 50.0,
  11. this.size = 32.0,
  12. @required this.icon,
  13. this.color = Colors.white,
  14. }) : super(key: key);
  15. @override
  16. build(context) {
  17. return Container(
  18. width: width,
  19. height: width,
  20. color: Color(Base.getRandomColor()),
  21. child: Center(
  22. child: Icon(icon, size: size, color: color),
  23. ),
  24. );
  25. }
  26. }

mainAxisSize

image.png

  1. Container(
  2. height: 100,
  3. color: Colors.grey,
  4. child: Row(
  5. mainAxisAlignment: MainAxisAlignment.center,
  6. mainAxisSize: MainAxisSize.min, //如果为min, mainAxisAlignment也就没意义上了
  7. children: [
  8. IconContainer(icon: Icons.home, width: 40.0),
  9. IconContainer(icon: Icons.search),
  10. IconContainer(icon: Icons.arrow_back, width: 60.0),
  11. ],
  12. ),
  13. );

textDirection

image.png

  1. Row(
  2. crossAxisAlignment: CrossAxisAlignment.start,
  3. mainAxisAlignment: MainAxisAlignment.start,
  4. textDirection: TextDirection.rtl,
  5. children: [
  6. IconContainer(icon: Icons.home, width: 40.0),
  7. IconContainer(icon: Icons.search),
  8. IconContainer(icon: Icons.arrow_back, width: 60.0),
  9. ],
  10. ),

verticalDirection

image.png

  1. Row(
  2. crossAxisAlignment: CrossAxisAlignment.start,
  3. mainAxisAlignment: MainAxisAlignment.start,
  4. verticalDirection: VerticalDirection.up,
  5. children: [
  6. IconContainer(icon: Icons.home, width: 40.0),
  7. IconContainer(icon: Icons.search),
  8. IconContainer(icon: Icons.arrow_back, width: 60.0),
  9. ],
  10. ),

Column

Column可以在垂直方向排列其子组件。参数和Row一样,不同的是布局方向为垂直,主轴纵轴正好相反,可类比Row来理解。

实际上,RowColumn都只会在主轴方向占用尽可能大的空间,而纵轴的长度则取决于他们最大子元素的长度。如果我们想让里面控件在整个手机屏幕中间对齐,我们有两种方法:

  • Column的宽度指定为屏幕宽度;这很简单,我们可以通过ConstrainedBoxSizedBox来强制更改宽度限制,例如:

    1. Container(
    2. constraints: BoxConstraints(minWidth: double.infinity),
    3. color: Colors.grey,
    4. child: Column(
    5. // crossAxisAlignment: CrossAxisAlignment.center,
    6. mainAxisAlignment: MainAxisAlignment.center,
    7. children: [
    8. IconContainer(icon: Icons.home, width: 40.0),
    9. IconContainer(icon: Icons.search),
    10. IconContainer(icon: Icons.arrow_back, width: 60.0),
    11. ],
    12. ),
    13. );
  • minWidth设为double.infinity,可以使宽度占用尽可能多的空间。

  • 使用Center Widget;

image.png

特殊情况

如果Row里面嵌套Row,或者Column里面再嵌套Column,那么只有最外面的RowColumn会占用尽可能大的空间,里面RowColumn所占用的空间为实际大小,下面以Column为例说明:

  1. Container(
  2. padding: EdgeInsets.all(16),
  3. color: Colors.grey,
  4. child: Column(
  5. mainAxisAlignment: MainAxisAlignment.start,
  6. mainAxisSize: MainAxisSize.max, //有效,外层Colum高度为整个屏幕
  7. children: [
  8. Container(
  9. color: Colors.green,
  10. child: Column(
  11. mainAxisSize: MainAxisSize.max, //无效,内层Colum高度为实际高度
  12. children: [
  13. IconContainer(icon: Icons.home, width: 40.0),
  14. IconContainer(icon: Icons.search),
  15. IconContainer(icon: Icons.arrow_back, width: 60.0),
  16. Text('hello'),
  17. ],
  18. ),
  19. ),
  20. ],
  21. ),
  22. );

image.png

如果想让里面的Column占满外部的Column,可以使用 Expanded 组件:

  1. Container(
  2. padding: EdgeInsets.all(16),
  3. color: Colors.grey,
  4. child: Column(
  5. mainAxisAlignment: MainAxisAlignment.start,
  6. mainAxisSize: MainAxisSize.max, //有效,外层Colum高度为整个屏幕
  7. children: [
  8. Expanded(
  9. child: Container(
  10. color: Colors.green,
  11. child: Column(
  12. mainAxisSize: MainAxisSize.max, //无效,内层Colum高度为实际高度
  13. children: [
  14. IconContainer(icon: Icons.home, width: 40.0),
  15. IconContainer(icon: Icons.search),
  16. IconContainer(icon: Icons.arrow_back, width: 60.0),
  17. Text('hello'),
  18. ],
  19. ),
  20. ),
  21. ),
  22. ],
  23. ),
  24. );

image.png