Flex
是 Flutter 中的一个小部件,用于创建一个弹性布局容器。它允许在一个轴上按比例分配可用空间,并根据需要调整子项的大小。
Flex
小部件有两个重要的属性:direction
和 children
。
direction
:指定了弹性容器的主轴方向。可以是水平方向(Axis.horizontal
)或垂直方向(Axis.vertical
)。children
:包含在弹性容器中的子项列表。Flex
使用一种类似于弹性盒子模型的方式来布局子项。子项可以使用 Expanded
小部件来指定它们在弹性容器中的相对比例。通过在子项中使用 Expanded
,可以根据需要调整子项的大小,并在弹性容器的主轴上按比例分配可用空间。
const Flex({
super.key,
required this.direction,
this.mainAxisAlignment = MainAxisAlignment.start,
this.mainAxisSize = MainAxisSize.max,
this.crossAxisAlignment = CrossAxisAlignment.center,
this.textDirection,
this.verticalDirection = VerticalDirection.down,
this.textBaseline,
this.clipBehavior = Clip.none,
super.children,
}) : assert(!identical(crossAxisAlignment, CrossAxisAlignment.baseline) || textBaseline != null, 'textBaseline is required if you specify the crossAxisAlignment with CrossAxisAlignment.baseline');
Container(
color: Colors.white,
child: Flex(
direction: Axis.horizontal,
children: [
Container(color: Colors.red, width: 300, height: 300, child: const Text('Hello World')),
Container(color: Colors.blue, width: 300, height: 300, child: const Text('Hello World')),
Container(color: Colors.green, width: 300, height: 300, child: const Text('Hello World')),
],
)
Axis
是一个枚举类型,用于表示二维空间中的两个基本方向。
以下是 Axis
的两个取值及其含义:
horizontal
:水平方向,表示从左到右的方向。vertical
:垂直方向,表示从上到下的方向。参考主轴对齐方式
!
MainAxisAlignment
是一个枚举类型,用于指定在 Flex 布局中子级容器沿主轴(main axis)的对齐方式。
以下是 MainAxisAlignment
的各个取值及其含义:
start
:尽可能靠近主轴的起始位置放置子级容器。end
:尽可能靠近主轴的结束位置放置子级容器。center
:将子级容器放置在主轴的中间位置。spaceBetween
:在子级容器之间均匀分布剩余空间。spaceAround
:在子级容器之间均匀分布剩余空间,并在第一个和最后一个子级容器之前及之后分配剩余空间的一半。spaceEvenly
:在子级容器之间均匀分布剩余空间,并在第一个和最后一个子级容器之前及之后分配相等的剩余空间。Container(
color: Colors.white,
child: Flex(
direction: Axis.horizontal,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(color: Colors.red, width: 300, height: 300, child: const Text('Hello World')),
Container(color: Colors.blue, width: 300, height: 300, child: const Text('Hello World')),
Container(color: Colors.green, width: 300, height: 300, child: const Text('Hello World')),
],
),
)
Container(
color: Colors.white,
child: Flex(
direction: Axis.vertical,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(color: Colors.red, width: 100, height: 100, child: const Text('Hello World')),
Container(color: Colors.blue, width: 100, height: 100, child: const Text('Hello World')),
Container(color: Colors.green, width: 100, height: 100, child: const Text('Hello World')),
],
),
)
MainAxisSize
是一个枚举类型,用于控制在主轴上子级容器应该占据多少空间。
在进行 Flex 布局时,沿主轴的可用空间会被分配给子级容器。在分配空间后,可能会有一些剩余的空闲空间。MainAxisSize
控制是否最大化或最小化空闲空间的量,同时受到传入的布局约束的限制。
以下是 MainAxisSize
的两个取值及其含义:
min
:最小化主轴上的空闲空间的量,受传入的布局约束的限制。如果传入的布局约束的 BoxConstraints.minWidth
或 BoxConstraints.minHeight
足够大,可能仍会有非零的空闲空间。如果传入的布局约束是无界的,并且任何子级容器具有非零的 FlexParentData.flex
值和 FlexFit.tight
的适应方式(由 Expanded
应用),则 RenderFlex
将断言,因为会存在无限剩余的空闲空间,而不能给予盒子无限的大小。max
:最大化主轴上的空闲空间的量,受传入的布局约束的限制。如果传入的布局约束的 BoxConstraints.maxWidth
或 BoxConstraints.maxHeight
足够小,可能仍然没有空闲空间。如果传入的布局约束是无界的,RenderFlex
将断言,因为会存在无限剩余的空闲空间,而不能给予盒子无限的大小。MainAxisSize.max
Container(
color: Colors.white,
child: Flex(
direction: Axis.horizontal,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
children: [
Container(color: Colors.red, width: 300, height: 300, child: const Text('Hello World')),
Container(color: Colors.blue, width: 300, height: 300, child: const Text('Hello World')),
Container(color: Colors.green, width: 300, height: 300, child: const Text('Hello World')),
],
),
)
MainAxisSize.min
Container(
color: Colors.white,
child: Flex(
direction: Axis.horizontal,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.min,
children: [
Container(color: Colors.red, width: 300, height: 300, child: const Text('Hello World')),
Container(color: Colors.blue, width: 300, height: 300, child: const Text('Hello World')),
Container(color: Colors.green, width: 300, height: 300, child: const Text('Hello World')),
],
)
交叉轴意思就是对应轴,主轴是水平方向,交叉轴就是垂直方向,反之亦然!
CrossAxisAlignment
是一个枚举类型,用于确定在 Flex 布局中子级容器沿交叉轴的对齐方式。
以下是 CrossAxisAlignment
的取值及其含义:
start
:将子级容器的起始边与交叉轴的起始边对齐。例如,在一个垂直方向(具有垂直轴)的列(Column
)中,如果文本方向为从左到右(TextDirection.ltr
),则子级容器的左边将与列的左边对齐。如果在水平方向使用此值,则需要提供 TextDirection
来确定起始边是左边还是右边。如果在垂直方向使用此值,则需要提供 VerticalDirection
来确定起始边是顶部还是底部。end
:尽可能地将子级容器与交叉轴的末端对齐。例如,在一个垂直方向(具有垂直轴)的列(Column
)中,如果文本方向为从左到右(TextDirection.ltr
),则子级容器的右边将与列的右边对齐。如果在水平方向使用此值,则需要提供 TextDirection
来确定末端是左边还是右边。如果在垂直方向使用此值,则需要提供 VerticalDirection
来确定末端是顶部还是底部。center
:将子级容器的中心与交叉轴的中心对齐。这是默认的交叉轴对齐方式。stretch
:要求子级容器填充交叉轴。这会导致传递给子级容器的约束在交叉轴上变为紧密约束。baseline
:将子级容器沿交叉轴以使其基线对齐。由于基线始终是水平的,所以该对齐方式适用于水平的主轴。如果主轴是垂直的,则此值会被视为 start
。对于水平的主轴,如果传递给 Flex 布局的最小高度约束超过了交叉轴的内在高度,子级容器将尽可能靠近顶部对齐,同时保持基线对齐。换句话说,额外的空间将位于所有子级容器的下方。没有基线的子级容器将与顶部对齐。CrossAxisAlignment.center
Container(
color: Colors.white,
child: Flex(
direction: Axis.horizontal,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(color: Colors.red, width: 300, height: 300, child: const Text('Hello World')),
Container(color: Colors.blue, width: 200, height: 200, child: const Text('Hello World')),
Container(color: Colors.green, width: 300, height: 300, child: const Text('Hello World')),
],
),
)
CrossAxisAlignment.center
Container(
color: Colors.white,
child: Flex(
direction: Axis.vertical,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Container(color: Colors.red, width: 200, height: 200, child: const Text('Hello World')),
Container(color: Colors.blue, width: 100, height: 100, child: const Text('Hello World')),
Container(color: Colors.green, width: 200, height: 200, child: const Text('Hello World')),
],
),
)
TextDirection
是一个枚举类型,用于表示文本的方向。
以下是 TextDirection
的取值及其含义:
rtl
:文本从右到左流动,例如阿拉伯语、希伯来语等。ltr
:文本从左到右流动,例如英语、法语等。Container(
color: Colors.white,
child: Flex(
direction: Axis.horizontal,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
textDirection: TextDirection.rtl,
children: [
Container(color: Colors.red, width: 300, height: 300, child: const Text('Hello World')),
Container(color: Colors.blue, width: 200, height: 200, child: const Text('Hello World')),
Container(color: Colors.green, width: 300, height: 300, child: const Text('Hello World')),
],
),
)
VerticalDirection
是一个枚举类型,用于确定垂直方向上的方向。
以下是 VerticalDirection
的取值及其含义:
up
:子级容器应从底部开始,并沿垂直方向堆叠到顶部。在此情况下,“start” 在底部,“end” 在顶部。down
:子级容器应从顶部开始,并沿垂直方向堆叠到底部。在此情况下,“start” 在顶部,“end” 在底部。Container(
color: Colors.white,
child: Flex(
direction: Axis.vertical,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
verticalDirection: VerticalDirection.up,
children: [
Container(color: Colors.red, width: 200, height: 200, child: const Text('Hello World')),
Container(color: Colors.blue, width: 150, height: 150, child: const Text('Hello World')),
Container(color: Colors.green, width: 200, height: 200, child: const Text('Hello World')),
],
),
)
TextBaseline
是一个枚举类型,用于指定文本对齐时使用的水平线。
以下是 TextBaseline
的取值及其含义:
alphabetic
:用于对齐字母字符底部的水平线。ideographic
:用于对齐表意字符的水平线。两个取值暂未看出明显区别,暂不做深究!
Container(
color: Colors.white,
child: const Flex(
direction: Axis.horizontal,
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.baseline,
textBaseline: TextBaseline.alphabetic,
children: [
Text('Hello World,Hello World,Hello World,\r\nHello World,Hello World,Hello World', style: TextStyle(fontSize: 50)),
Text('訾博', style: TextStyle(fontSize: 30)),
],
),
)
枚举类型 Clip
是用于指定小部件内容剪辑方式的选项。
以下是 Clip
的取值及其含义:
none
:没有剪辑。这是大多数小部件的默认选项。如果内容没有超出小部件的边界,不会进行任何剪辑,也不会产生性能开销。如果内容超出边界,则需要显式指定其他的剪辑选项。hardEdge
:剪辑内容,但不应用反锯齿。这种方式会导致剪辑边缘呈锯齿状,适用于容器为轴对齐矩形或轴对齐圆角矩形且圆角半径非常小的情况。比起其他剪辑模式,速度较快但比 none
模式慢。antiAlias
:剪辑内容并应用反锯齿。这种方式会使剪辑边缘呈现平滑的外观。速度比 antiAliasWithSaveLayer
快,但比 hardEdge
模式慢。在处理圆形和弧形时常用的方式。antiAliasWithSaveLayer
:剪辑内容并应用反锯齿,同时在剪辑后立即创建一个离屏缓冲区。所有后续绘制操作都在该缓冲区上进行,最后再进行剪辑和合成。这种方式非常慢,但与 antiAlias
不同,它会引入一个离屏缓冲区,改变了绘制的语义。这种方式很少使用,仅在特定情况下才需要,例如在图像上叠加不同背景颜色时。如果可以避免在同一位置叠加多个颜色(例如只在图像缺失的地方使用背景颜色),则使用 antiAlias
模式会更快速。代码示例看不出特别效果,暂不做深究。
Row = Flex + direction: Axis.horizontal
class Row extends Flex {
const Row({
super.key,
super.mainAxisAlignment,
super.mainAxisSize,
super.crossAxisAlignment,
super.textDirection,
super.verticalDirection,
super.textBaseline,
super.children,
}) : super(
direction: Axis.horizontal,
);
}
Container(
color: Colors.white,
child: Row(
children: [
Container(color: Colors.red, width: 300, height: 300, child: const Text('Hello World')),
Container(color: Colors.blue, width: 300, height: 300, child: const Text('Hello World')),
Container(color: Colors.green, width: 300, height: 300, child: const Text('Hello World')),
],
),
)
Column = Flex + direction: Axis.vertical
class Column extends Flex {
const Column({
super.key,
super.mainAxisAlignment,
super.mainAxisSize,
super.crossAxisAlignment,
super.textDirection,
super.verticalDirection,
super.textBaseline,
super.children,
}) : super(
direction: Axis.vertical,
);
}
Container(
color: Colors.white,
child: Column(
children: [
Container(color: Colors.red, width: 200, height: 200, child: const Text('Hello World', style: TextStyle(fontSize: 40))),
Container(color: Colors.blue, width: 150, height: 150, child: const Text('Hello World', style: TextStyle(fontSize: 40))),
Container(color: Colors.green, width: 200, height: 200, child: const Text('Hello World', style: TextStyle(fontSize: 40))),
],
),
)