Flutter入门-Flex布局类组件-Row、Column、Flexible、Spacer以及Expand

454 阅读4分钟

Flutter中的Flex布局和Web中的Flex布局非常类似,估计是借鉴了Web中Flex布局,所以很多属性和表现,都跟其相似。但是注意一点,自身不带滚动属性,如果超出了一行,在debug下面则会显示溢出的提示

Row和Column

Row以及Column都是多子节点容器,类似Web中的某个元素其display属性为flex,实际上它们也都是Flex的子类,它们的具体实现也都是由Flex完成,只是参数不同,更具体点就是主轴方向不同,以Row为例,其构造函数如下:

Row({
  Key key,
  MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
  MainAxisSize mainAxisSize = MainAxisSize.max,
  CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
  TextDirection textDirection,
  VerticalDirection verticalDirection = VerticalDirection.down,
  TextBaseline textBaseline,
  List<Widget> children = const <Widget>[],
})

它们的direction属性分别为 // Row
direction: Axis.horizontal,
/// Column
direction: Axis.vertical,

MainAxisAlignment:主轴方向上的对齐方式,会对child的位置起作用,默认是start。

其中MainAxisAlignment枚举值:

  • center:将children放置在主轴的中心;
  • end:将children放置在主轴的末尾;
  • spaceAround:将主轴方向上的空白区域均分,使得children之间的空白区域相等,但是首尾child的空白区域为1/2;
  • spaceBetween:将主轴方向上的空白区域均分,使得children之间的空白区域相等,首尾child都靠近首尾,没有间隙;
  • spaceEvenly:将主轴方向上的空白区域均分,使得children之间的空白区域相等,包括首尾child;
  • start:将children放置在主轴的起点;

其中spaceAround、spaceBetween以及spaceEvenly的区别,就是对待首尾child的方式。其距离首尾的距离分别是空白区域的1/2、0、1。

image.png

MainAxisSize:在主轴方向占有空间的值,默认是max。

MainAxisSize的取值有两种:

  • max:根据传入的布局约束条件,最大化主轴方向的可用空间;
  • min:与max相反,是最小化主轴方向的可用空间;

image.png CrossAxisAlignment:children在交叉轴方向的对齐方式,与MainAxisAlignment略有不同。

CrossAxisAlignment枚举值有如下几种:

  • baseline:在交叉轴方向,使得children的baseline对齐;
  • center:children在交叉轴上居中展示;
  • end:children在交叉轴上末尾展示;
  • start:children在交叉轴上起点处展示;
  • stretch:让children填满交叉轴方向;

image.png TextDirection:阿拉伯语系的兼容设置,一般无需处理。

VerticalDirection:定义了children摆放顺序,默认是down。

VerticalDirection枚举值有两种:

  • down:从top到bottom进行布局;
  • up:从bottom到top进行布局。

image.png top对应Row以及Column的话,就是左边和顶部,bottom的话,则是右边和底部。

TextBaseline:使用的TextBaseline的方式,有两种,

  • TextBaseline.alphabetic:与字母基线对齐;
  • TextBaseline.ideographic:与表意字符基线对齐;

如下分别为不设置 textBaseline 属性、设置 TextBaseline.alphabetic 和 TextBaseline.ideographic,对比效果:

image.png

clipBehavior 当子组件超出容器时的裁剪行为,设置方式如下:

  • Clip.none:不裁剪
  • Clip.hardEdge:裁剪
  • Clip.antiAlias:裁剪,抗锯齿
  • Clip.antiAliasWithSaveLayer:裁剪,抗锯齿

Flexible、Expand

前面说ow以及Column都是多子节点容器,类似Web中的某个元素其display属性为flex,那么 Flexible、Spacer以及Expand就是加了flex属性的子节点

  1. fit属性
    Flexible 的 fit 属性默认为 FlexFit.loose,而 Expanded 继承 Flexible,其 fit 属性指定为 FlexFit.tight,可设置的 fit 属性如下:

    • tight:强制填充可利用的空间;
    • loose:不强制填充可利用空间,Widget自身大小。
  2. flex属性
    Flexible 的 flex属性是弹性系数,可以类比flex-grow 对比效果如下:

Expanded 可以使 Row、Column、Flex 里面的组件填充沿着主轴可利用的空间,如果多个 Widget 都使用了 Expanded 组件,可以使用 Expanded 的 flex 属性按照比例分配主轴空间

Row(
    mainAxisAlignment: MainAxisAlignment.start,
    mainAxisSize: MainAxisSize.max,
    children: <Widget>[
      Expanded(
        flex: 1,
        child: Container(
            width: 50,
            height: 50,
            color: Colors.red,
            child: const Center(
              child: Text(
                "A",
                style: TextStyle(fontSize: 20, color: Colors.white),
              ),
            )),
      ),
      Expanded(
        flex: 2,
        child: Container(
            width: 50, // Row Expanded下width无效
            height: 50, // Column Expanded下height无效
            color: Colors.green,
            child: const Center(
              child: Text(
                "B",
                style: TextStyle(fontSize: 20, color: Colors.white),
              ),
            )),
      ),
      Container(
          width: 50,
          height: 50,
          color: Colors.yellow,
          child: const Center(
            child: Text(
              "C",
              style: TextStyle(fontSize: 20, color: Colors.white),
            ),
          )),
    ],
  );

显示效果如下:

image.png

Spacer

Spacer 用来调节 Widget 之间的间距,会占据所有的剩余空间,因此 MainAxisAlignment 的设置将无效,Spacer 的属性 flex 用于设置剩余空间的分配权重,默认值为 1,表示占据所有剩余空间,如果两个以上 Spacer 则按照 flex 分配剩余空间

class RowSamplePage1 extends StatelessWidget {  
  @override  
  Widget build(BuildContext context) {  
    return Scaffold(  
        appBar: AppBar(  
          title: Text("Row Sample"),  
          centerTitle: true,  
        ),  
        body: ConstrainedBox(  
          constraints: BoxConstraints(maxHeight: 150),  
          child: Row(  
            children: <Widget>\[  
              Container(  
                width: 80,  
                height: 80,  
                color: Colors.red,  
              ),  
              Spacer(flex: 1,),  
              Container(  
                width: 80,  
                height: 80,  
                color: Colors.green,  
              ),  
              Spacer(flex: 2,),  
              Container(  
                width: 80,  
                height: 80,  
                color: Colors.yellow,  
              ),  
            \],  
          ),  
        ));  
  }  
}  

image.png