Flutter(八)线性布局-Row&Column

857 阅读6分钟

「这是我参与11月更文挑战的第6天,活动详情查看:2021最后一次更文挑战

线性布局也就是子部件沿水平或者垂直方向排列。在Flutter中线性布局是通过RowColumn来实现的;这类似于AndroidLinearLayout的控件;而RowColumn都继承自Flex(弹性布局);

主轴和纵轴

对于线性布局而言,是由主轴纵轴之分的;

  • 如果布局是沿水平方向,那么主轴就是指水平方向,纵轴就是垂直方向
  • 如果布局是沿垂直方向,那么主轴就是指垂直方向,纵轴就是水平方向
  • MainAxisAlignment主轴对齐;
  • CrossAxisAlignment纵轴对齐;

准备工作

在之前的学习中,我们已经知道了Container不见会根据其内部的子部件改变自身大小,比如: image.png一个默认的满屏的黄色背景的Container,如果我们在其内部添加一个子部件Textimage.png 原来满屏的黄色背景的Container变成了Text部件一样的大小; ​

接下来我们再来看一个Container的属性:alignment对齐方式,其定义如下:

final AlignmentGeometry? alignment;

aligment需要一个AlignmentGeometry类型的值,表示子部件在父部件中的起始位置。AlignmentGeometry是一个抽象类,它有两个常用的子类:AlignmentFractionOffset

这里我们先使用Alignment来进行布局,其构造函数为:

const Alignment(this.x, this.y)

x,y取值范围为-11;中心点是(0,0)

image.png 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.ltrMainAxisAlignment.start表示左对齐;
        • TextDirection.rtlMainAxisAlignment.start表示右对齐;
      • MainAxisAlignment.endMainAxisAlignment.start表示的初始化对齐方向时相反的;
      • MainAxisAlignment.center表示居中对齐;
    • 可以理解为:textDirectionmainAxisAlignment的参考系;
  • verticalDirection:表示Row纵轴(垂直)的对齐方向;
    • VerticalDirection.down:表示从上到下;
    • VerticalDirection.up:表示从下到上;
  • crossAxisAlignment:表示子部件在纵轴方向上的对齐方式;Row的高度等于子部件中最高的子元素的高度;其取之和MainAxisAlignment一样包含startendcenter三个值;不同的是其参考系是verticalDirection
    • verticalDirection值为VerticalDirection.down时,CrossAxisAlignment.start表示顶部对齐;
    • verticalDirection值为VerticalDirection.up时,CrossAxisAlignment.start表示底部对齐;
    • CrossAxisAlignment.endCrossAxisAlignment.start相反;
  • children子部件数组;

我们现在先在Row中添加三个Text,看一下默认效果: image.png 默认三个Text为居左对齐;红色线框区域为Row的区域,两条蓝色线交叉点为Row的中心点; 因为Row是横向的,所以此时Alignmentx的值对Row的布局是没有影响的: image.png

同样的y值对Column的布局也是没有影响的;

接下来我们将RowtextDirection设置为TextDirection.rtl看一下运行效果: image.png 三个Text的初始化顺序变为从右开始; 为了便于查看效果,我们将多个Row放在界面中,从上到下排列,效果如图: image.png image.png

  • 第一行:默认居中对齐;
  • 第二行:由于设置了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来看一下效果: image.png

本来Row中从左到右布局的三个Text,换成Column之后变为了从上到下布局,并且因为Alignmentx-1,所以在在水平方向上,先是在了屏幕的最左侧;

关于 MainAxisAlignment的补充

MainAxisAlignment是一个枚举类型,其定义如下:

enum MainAxisAlignment {
  start,
  end,
  center,
  spaceBetween,
  spaceAround,
  spaceEvenly,
}

我们发现MainAxisAlignment除了startendcenter三个之和,还有spaceBetweenspaceAroundspaceEvenly三个值,那么这三个值的效果是什么样子的呢?

spaceBetween

spaceBetween意思是:所有的子部件布局完成之后,剩下的空间平均分布到几个子部件之间; ​

演示效果如下: image.png

spaceAround

spaceAround意思是:所有的子部件布局完成之后,剩下的空间平均分布到几个子部件周围; ​

为了更好的演示效果,我们此处改变字体大小之后看效果如下: image.png image.png

spaceEvenly

spaceEvenly意思是:所有的子部件布局完成之后,剩下的空间和子部件一起平均分; image.png

图中粉红色横线表示的间隔距离相等;

关于CrossAxisAlignment的补充

除了我们常用的枚举值之外,CrossAxisAlignment还有baseline的枚举值,那么效果如何呢? image.png 将值改为baseline之后,工程直接报错,这是因为baseline这个枚举值要结合textBaseline属性进行使用;效果如下: image.png

最终效果:三个Text部件虽然没有对齐,但是其中的文字底部对齐了;

关于Expanded的补充

Expandeed是一个自适应部件;我们简单看一下效果: image.png 使用Expanded部件把Text包起来之后,Text部件文字超过限制之后,可以自己换行显示了; ​

我们继续修改代码: image.png 我们把Text包括在Container里边,此时发现Container也自适应的在主轴方向上进行了拉伸;

许哟啊注意的是Expanded所在的children数组不可以使用const修饰;

此时,我们修改Container的高度: image.png 高度生效了;

  • Row中,给Expanded的子部件设置高度有意义,宽度无意义
  • Column中,给Expanded的子部件设置高度无意义,宽度有意义;

Expanded在主轴方向上不会留下间隙,将被Expanded拉伸;