开篇
Row 和 Column 分别是 Flutter 中的水平和垂直布局,它们都是 MultiChildRenderObjectWidget,所以它们都是可以渲染多个孩子的控件,而它们是如何渲染孩子的大小和位置的则是有 renderObject 定义的。它们的继承关系图如下:


MainAxisAlignment 和 CrossAxisAlignment
Row、Column 的布局特性和 MainAxisAlignment(主轴)和 CrossAxisAlignment(交叉轴)有关。主轴是与当前控件方向一致的轴,而交叉轴就是与当前控件方向垂直方向的轴。主轴和交叉轴是相对于的,它们主要用于控制 Row,Column 的子控件排列位置。因此,在 Row 中,MainAxisAlignment 的方向是水平的,默认的起始位置在左边,排列方向是从左至右;而 CrossAxisAlignment 的方向则是垂直的,默认的起始位置在中间,排列方向是从上到下。
相对的,在 Column 中,MainAxisAlignment 的方向是垂直的,默认起始位置在上边,排列方向是从上至下;CrossAxisAlignment 的方向则是水平的,默认的起始位置在中间,排列方向是从左到右。另外,textDirection 和 verticalDirection 可以分别改变水平和垂直方向的起始位置和排列方向。
MainAxisAlignment 的值:
enum MainAxisAlignment {
//将子控件放在主轴的开始位置
start,
//将子控件放在主轴的结束位置
end,
//将子控件放在主轴的中间位置
center,
//将主轴空白位置进行均分,排列子元素,手尾没有空隙
spaceBetween,
//将主轴空白区域均分,使中间各个子控件间距相等,首尾子控件间距为中间子控件间距的一半
spaceAround,
//将主轴空白区域均分,使各个子控件间距相等
spaceEvenly,
}
CrossAxisAlignment 取值:
enum CrossAxisAlignment {
//将子控件放在交叉轴的起始位置
start,
//将子控件放在交叉轴的结束位置
end,
//将子控件放在交叉轴的中间位置
center,
//使子控件填满交叉轴
stretch,
//将子控件放在交叉轴的上,并且与基线相匹配(不常用)
baseline,
}
textDirection 取值:
enum TextDirection {
//从右到左排列
rtl,
//从左到右排列
ltr,
}
VerticalDirection 取值
enum VerticalDirection {
//从上到下
up,
//从下到上
down,
}
定义控件 Box
为了实例说明的方便,这里专门封装一个 box 控件来说明 Row 和 Column 布局特性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| class Box extends StatelessWidget {
String index; double boxSize = 100.0;
Box(String index) { this.index = index; }
@override Widget build(BuildContext context) { return Container( width: boxSize, height: boxSize, alignment: Alignment.center, decoration: BoxDecoration( gradient: LinearGradient( colors: [Colors.orangeAccent, Colors.orange, Colors.deepOrange] ) ), child: Text( index, style: TextStyle( color: Colors.white, fontSize: 20, fontWeight: FontWeight.bold ), ), ); }
}
|
Row
(1)Row 的默认情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class _MyHomePageState extends State<MyHomePage> {
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Container( color: Colors.green, height: 200.0, child: Row( children: <Widget>[ Box("1"), Box("2"), Box("3"), Box("4") ], ), ), ); }
}
|

可以看出来,Row 的默认起始位置在左边,排列方向是从左到右。也就是:
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
textDirection: TextDirection.ltr,
verticalDirection: VerticalDirection.down,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class _MyHomePageState extends State<MyHomePage> {
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Container( color: Colors.green, height: 200.0, child: Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, textDirection: TextDirection.ltr, verticalDirection: VerticalDirection.down, children: <Widget>[ Box("1"), Box("2"), Box("3"), Box("4") ], ), ), ); }
}
|

(2)使用 textDirection 和 verticalDirection 将默认值取全反
为了看出 verticalDirection: VerticalDirection.up 的效果,故意把 crossAxisAlignment 设置为了 CrossAxisAlignment.start
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class _MyHomePageState extends State<MyHomePage> {
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Container( color: Colors.green, height: 200.0, child: Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, textDirection: TextDirection.rtl, verticalDirection: VerticalDirection.up, children: <Widget>[ Box("1"), Box("2"), Box("3"), Box("4") ], ), ), ); }
}
|

(3)使用 verticalDirection 只改变垂直方向的默认位置和排列方向
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class _MyHomePageState extends State<MyHomePage> {
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Container( color: Colors.green, height: 200.0, child: Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, textDirection: TextDirection.ltr, verticalDirection: VerticalDirection.up, children: <Widget>[ Box("1"), Box("2"), Box("3"), Box("4") ], ), ), ); }
}
|

(4)使用 textDirection 只改变水平方向的默认位置和排列方向
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class _MyHomePageState extends State<MyHomePage> {
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Container( color: Colors.green, height: 200.0, child: Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, textDirection: TextDirection.rtl, verticalDirection: VerticalDirection.down, children: <Widget>[ Box("1"), Box("2"), Box("3"), Box("4") ], ), ), ); }
}
|

(5)居中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class _MyHomePageState extends State<MyHomePage> {
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Container( color: Colors.green, height: 200.0, child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, textDirection: TextDirection.ltr, verticalDirection: VerticalDirection.down, children: <Widget>[ Box("1"), Box("2"), Box("3"), Box("4") ], ), ), ); }
}
|

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class _MyHomePageState extends State<MyHomePage> {
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Container( color: Colors.green, height: 200.0, child: Row( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, textDirection: TextDirection.rtl, verticalDirection: VerticalDirection.down, children: <Widget>[ Box("1"), Box("2"), Box("3"), Box("4") ], ), ), ); }
}
|

(6)填满交叉轴
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| class _MyHomePageState extends State<MyHomePage> {
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Container( color: Colors.green, height: 200.0, child: Row( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.stretch, textDirection: TextDirection.ltr, verticalDirection: VerticalDirection.down, children: <Widget>[ Box("1"), Box("2"), Box("3"), Box("4") ], ), ), ); }
}
|

Column
(1)Column 的默认情况
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| class _MyHomePageState extends State<MyHomePage> {
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Container( color: Colors.green, height: 600.0, width: 400.0, child: Column( children: <Widget>[ Box("1"), Box("2"), Box("3"), Box("4") ], ), ), ); }
}
|

也就是 Column 的默认情况是:
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.center,
textDirection: TextDirection.ltr,
verticalDirection: VerticalDirection.down,
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class _MyHomePageState extends State<MyHomePage> {
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Container( color: Colors.green, height: 600.0, width: 400.0, child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, textDirection: TextDirection.ltr, verticalDirection: VerticalDirection.down, children: <Widget>[ Box("1"), Box("2"), Box("3"), Box("4") ], ), ), ); }
}
|

(2)使用 textDirection 和 verticalDirection 将默认值改为全反
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class _MyHomePageState extends State<MyHomePage> {
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Container( color: Colors.green, height: 600.0, width: 400.0, child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, textDirection: TextDirection.rtl, verticalDirection: VerticalDirection.up, children: <Widget>[ Box("1"), Box("2"), Box("3"), Box("4") ], ), ), ); }
}
|

(3)使用 verticalDirection 只改变垂直方向的默认位置和排列方向
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class _MyHomePageState extends State<MyHomePage> {
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Container( color: Colors.green, height: 600.0, width: 400.0, child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, textDirection: TextDirection.ltr, verticalDirection: VerticalDirection.up, children: <Widget>[ Box("1"), Box("2"), Box("3"), Box("4") ], ), ), ); }
}
|

(4)使用 textDirection 只改变水平方向的默认位置和排列方向
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class _MyHomePageState extends State<MyHomePage> {
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Container( color: Colors.green, height: 600.0, width: 400.0, child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start, textDirection: TextDirection.rtl, verticalDirection: VerticalDirection.down, children: <Widget>[ Box("1"), Box("2"), Box("3"), Box("4") ], ), ), ); }
}
|

(5)居中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class _MyHomePageState extends State<MyHomePage> {
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Container( color: Colors.green, height: 600.0, width: 400.0, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, textDirection: TextDirection.ltr, verticalDirection: VerticalDirection.down, children: <Widget>[ Box("1"), Box("2"), Box("3"), Box("4") ], ), ), ); }
}
|

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class _MyHomePageState extends State<MyHomePage> {
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Container( color: Colors.green, height: 600.0, width: 400.0, child: Column( mainAxisAlignment: MainAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center, textDirection: TextDirection.ltr, verticalDirection: VerticalDirection.up, children: <Widget>[ Box("1"), Box("2"), Box("3"), Box("4") ], ), ), ); }
}
|

(6)填满交叉轴
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class _MyHomePageState extends State<MyHomePage> {
@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Container( color: Colors.green, height: 600.0, width: 400.0, child: Column( mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.stretch, textDirection: TextDirection.ltr, verticalDirection: VerticalDirection.down, children: <Widget>[ Box("1"), Box("2"), Box("3"), Box("4") ], ), ), ); }
}
|
