Flutter 之 弹性布局 (Row、Column) (十一)

1、Flex

弹性布局允许子组件按照必定比例来分配父容器空间

Flex组件和Row、Column属性主要的区别就是多一个direction。
当direction的值为Axis.horizontal的时候,则是Row。
当direction的值为Axis.vertical的时候,则是Column。

它们之中都有主轴(MainAxis)和交叉轴(CrossAxis)的概念:

  • 对于Row来说,主轴(MainAxis)和交叉轴(CrossAxis)分别是下图

    Flutter 之 弹性布局 (Row、Column)  (十一)

  • 对于Column来说,主轴(MainAxis)和交叉轴(CrossAxis)分别是下图

    Flutter 之 弹性布局 (Row、Column)  (十一)

2. 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:表明水平方向子组件的布局顺序(是从左往右还是从右往左),默认为系统当前Locale环境的文本方向(如中文、英语都是从左往右,而阿拉伯语是从右往左)。对于Row,它决定的是主轴的布局顺序,对于‘Column’ ,它决定的是交叉轴的布局顺序

  • mainAxisSize:表明Row在主轴(水平)方向占用的空间,默认是MainAxisSize.max,表明尽可能多的占用水平方向的空间,此时无论子 widgets 实际占用多少水平空间,Row的宽度始终等于水平方向的最大宽度;而MainAxisSize.min表明尽可能少的占用水平空间,当子组件没有占满水平剩余空间,则Row的实际宽度等于所有子组件占用的的水平空间;

  • mainAxisAlignment:表明子组件在Row所占用的水平空间内对齐方式,如果mainAxisSize值为MainAxisSize.min,则此属性无意义,由于子组件的宽度等于Row的宽度。只有当mainAxisSize的值为MainAxisSize.max时,此属性才有意义,MainAxisAlignment.start表明沿textDirection的初始方向对齐,如textDirection取值为TextDirection.ltr时,则MainAxisAlignment.start表明左对齐,textDirection取值为TextDirection.rtl时表明从右对齐。而MainAxisAlignment.endMainAxisAlignment.start正好相反;MainAxisAlignment.center表明居中对齐。读者可以这么理解:textDirectionmainAxisAlignment的参考系。

  • verticalDirection:表明Row纵轴(垂直)的对齐方向,默认是VerticalDirection.down,表明从上到下。对于Row,它决定的是交叉轴的布局顺序,对于‘Column’ ,它决定的是主轴的布局顺序

  • crossAxisAlignment:表明子组件在纵轴方向的对齐方式,Row的高度等于子组件中最高的子元素高度,它的取值和MainAxisAlignment一样(包含startendcenter三个值),不同的是crossAxisAlignment的参考系是verticalDirection,即verticalDirection值为VerticalDirection.downcrossAxisAlignment.start指顶部对齐,verticalDirection值为VerticalDirection.up时,crossAxisAlignment.start指底部对齐;而crossAxisAlignment.endcrossAxisAlignment.start正好相反;

  • children :子组件数组。

2.1 案例

示例1 – 基本使用

/**
   * Row特点
   *  - 水平方向尽可能占据比较大的空间
   *    * 水平方向也希望包裹内容,那么设置mainAxisSize = min
   *  - 垂直方向包裹内容
   * mainAxisAlignment:
   *  - start: 主轴的开始位置挨个摆放元素(默认)
   *  - end: 主轴的结束位置挨个摆放元素
   *  - center: 主轴的中心点对齐
   *  - spaceBetween:左右两边的间距为0,其他元素之间平分间距
   *  - spaceAround: 左右两边的间距是其他元素之间间距的一半
   *  - spaceEvenly: 所有的间距平分空间
   * 
   * CrossAxisAlignment:
   *  - start:交叉轴的起始位置对齐
   *  - end: 交叉轴的结束位置对齐
   *  - center:交叉轴的中心点对齐 (默认)
   *  - stretch:先Row占据交叉轴尽可能大的空间,将所有的子Widget交叉轴的高度,拉伸到最大
   *  - baseline:基线对齐(必须有文本的时候才起作用) 要设置textBaseline 类型
   *
*/
class RowDemo1 extends StatelessWidget {
  const RowDemo1({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      crossAxisAlignment: CrossAxisAlignment.end,
      verticalDirection: VerticalDirection.down,
      children: [
        Container(width: 80, height: 60, color: Colors.red),
        Container(width: 100, height: 100, color: Colors.blue),
        Container(width: 90, height: 60, color: Colors.orange),
        Container(width: 50, height: 120, color: Colors.purple),
      ],
    );
  }
}

Flutter 之 弹性布局 (Row、Column)  (十一)

示例2 – 基线对齐
基线是英文字母X的下端两点连成的一条线

class RowDemo2 extends StatelessWidget {
  const RowDemo2({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.center,
      crossAxisAlignment: CrossAxisAlignment.baseline,
      textBaseline: TextBaseline.alphabetic,
      children: [
        Container(
            width: 80,
            height: 60,
            color: Colors.red,
            child: Text("ABX", style: TextStyle(fontSize: 25))),
        Container(
            width: 100,
            height: 100,
            color: Colors.blue,
            child: Text("ABX", style: TextStyle(fontSize: 20))),
        Container(
            width: 90,
            height: 60,
            color: Colors.orange,
            child: Text("ABX", style: TextStyle(fontSize: 10))),
        Container(
            width: 50,
            height: 120,
            color: Colors.purple,
            child: Text("ABX", style: TextStyle(fontSize: 18))),
      ],
    );
  }
}

Flutter 之 弹性布局 (Row、Column)  (十一)

示例3 – 水平方向包裹

class RowDemo3 extends StatelessWidget {
  const RowDemo3({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ElevatedButton(
      onPressed: () {},
      child: Row(
        // 主轴方向 包裹内容
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(Icons.people),
          Text("UserName"),
        ],
      ),
    );
  }
}

Flutter 之 弹性布局 (Row、Column)  (十一)

3. Column

Column可以沿垂直方向排列其子widget。定义如下:

  Column({
    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>[],
  })

3.1 示例

Column 基本使用 示例

class ColumnDemo1 extends StatelessWidget {
  const ColumnDemo1({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.start,
      textDirection: TextDirection.ltr, // 水平方向 显示方向 默认 ltr
      crossAxisAlignment: CrossAxisAlignment.end,
      verticalDirection: VerticalDirection.up, // 垂直方向 显示方向 默认down
      children: [
        Container(width: 80, height: 60, color: Colors.red),
        Container(width: 100, height: 100, color: Colors.blue),
        Container(width: 90, height: 60, color: Colors.orange),
        Container(width: 50, height: 120, color: Colors.purple),
      ],
    );
  }
}

Flutter 之 弹性布局 (Row、Column)  (十一)

再看一个示例

class _MSHomeContentState extends State<MSHomeContent> {
  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: [
        Text("Hello World"),
        Text("Hi"),
      ],
    );
  }
}

运行效果如下:

Flutter 之 弹性布局 (Row、Column)  (十一)

我们发现文本并没有居中?

解释:

  • 由于我们没有指定Column的mainAxisSize,所以使用默认值MainAxisSize.max,则Column会在垂直方向占用尽可能多的空间,此例中会占满整个屏幕高度。
  • 由于我们指定了 crossAxisAlignment 属性为CrossAxisAlignment.center,那么子项在Column纵轴方向(此时为水平方向)会居中对齐。注意,在水平方向对齐是有边界的,总宽度为Column占用空间的实际宽度,而实际的宽度取决于子项中宽度最大的Widget。在本例中,Column有两个子Widget,而显示“world”的Text宽度最大,所以Column的实际宽度则为Text(“world”) 的宽度,所以居中对齐后Text(“hi”)会显示在Text(“world”)的中间部分。

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

  • 将Column的宽度指定为屏幕宽度;这很简单,我们可以通过ConstrainedBox、SizedBox、Container

class ColumnDemo2 extends StatelessWidget {
  const ColumnDemo2({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ConstrainedBox(
      constraints: BoxConstraints(minWidth: double.infinity),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Text("Hello World"),
          Text("Hi"),
        ],
      ),
    );
  }
}

  • 使用Center组件对齐

class ColumnDemo3 extends StatelessWidget {
  const ColumnDemo3({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.center,
        children: [
          Text("Hello World"),
          Text("Hi"),
        ],
      ),
    );
  }
}

运行效果如下:

Flutter 之 弹性布局 (Row、Column)  (十一)

4. Row Column 嵌套

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

class ColumnDemo4 extends StatelessWidget {
  const ColumnDemo4({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.green,
      padding: EdgeInsets.all(8),
      child: Column(
        mainAxisSize: MainAxisSize.max, // //有效,外层Colum高度为整个屏幕
        children: [
          Container(
            color: Colors.red,
            child: Column(
              mainAxisSize: MainAxisSize.max, // //无效,内层Colum高度为实际高度
              children: [
                Text("Hello World"),
                Text("Hi"),
              ],
            ),
          )
        ],
      ),
    );
  }
}

Flutter 之 弹性布局 (Row、Column)  (十一)

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

class ColumnDemo5 extends StatelessWidget {
  const ColumnDemo5({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Container(
      color: Colors.green,
      padding: EdgeInsets.all(8),
      child: Column(
        mainAxisSize: MainAxisSize.max, // //有效,外层Colum高度为整个屏幕
        children: [
          Expanded(
            child: Container(
              color: Colors.red,
              child: Column(
                mainAxisSize: MainAxisSize.max, // //无效,内层Colum高度为实际高度
                children: [
                  Text("Hello World"),
                  Text("Hi"),
                ],
              ),
            ),
          )
        ],
      ),
    );
  }
}

Flutter 之 弹性布局 (Row、Column)  (十一)

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容