## 線性布局Row和Column
所謂線性布局,即指沿水平或垂直方向排布子Widget。Flutter中通過Row和Column來實現線性布局,類似于Android中的LinearLayout控件。Row和Column都繼承自Flex,我們將在彈性布局一節中詳細介紹Flex。
### 主軸和縱軸
對于線性布局,有主軸和縱軸之分,如果布局是沿水平方,那么主軸就指是水平方向,而縱軸即垂直方向;如果布局沿垂直方向,那么主軸就是指垂直方向,而縱軸就是水平方向。在線性布局中,有兩個定義對齊方式的枚舉類MainAxisAlignment和CrossAxisAlignment,分別代表主軸對齊和縱軸對齊。
### Row
Row可以在水平方向排列其子widget。定義如下:
```
Row({
...
TextDirection textDirection,
MainAxisSize mainAxisSize = MainAxisSize.max,
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
VerticalDirection verticalDirection = VerticalDirection.down,
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
List<Widget> children = const <Widget>[],
})
```
- textDirection:表示水平方向子widget的布局順序(是從左往右還是從右往左),默認為系統當前Locale環境的文本方向(如中文、英語都是從左往右,而阿拉伯語是從右往左)。
- mainAxisSize:表示Row在主軸(水平)方向占用的空間,默認是`MainAxisSize.max`,表示盡可能多的占用水平方向的空間,此時無論子widgets實際占用多少水平空間,Row的寬度始終等于水平方向的最大寬度;而`MainAxisSize.min`表示盡可能少的占用水平空間,當子widgets沒有占滿水平剩余空間,則Row的實際寬度等于所有子widgets占用的的水平空間;
- mainAxisAlignment:表示子Widgets在Row所占用的水平空間內對齊方式,如果mainAxisSize值為`MainAxisSize.min`,則此屬性無意義,因為子widgets的寬度等于Row的寬度。只有當mainAxisSize的值為`MainAxisSize.max`時,此屬性才有意義,`MainAxisAlignment.start`表示沿textDirection的初始方向對齊,如textDirection取值為`TextDirection.ltr`時,則`MainAxisAlignment.start`表示左對齊,textDirection取值為`TextDirection.rtl`時表示從右對齊。而`MainAxisAlignment.end`和`MainAxisAlignment.start`正好相反;`MainAxisAlignment.center`表示居中對齊。讀者可以這么理解:textDirection是mainAxisAlignment的參考系。
- verticalDirection:表示Row縱軸(垂直)的對齊方向,默認是`VerticalDirection.down`,表示從上到下。
- crossAxisAlignment:表示子Widgets在縱軸方向的對齊方式,Row的高度等于子Widgets中最高的子元素高度,它的取值和MainAxisAlignment一樣(包含`start`、`end`、 `center`三個值),不同的是crossAxisAlignment的參考系是verticalDirection,即verticalDirection值為`VerticalDirection.down`時`crossAxisAlignment.start`指頂部對齊,verticalDirection值為`VerticalDirection.up`時,`crossAxisAlignment.start`指底部對齊;而`crossAxisAlignment.end`和`crossAxisAlignment.start`正好相反;
- children :子Widgets數組。
### 示例
請閱讀下面代碼,想象一下運行的結果:
```
Column(
//測試Row對齊方式,排除Column默認居中對齊的干擾
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(" hello world "),
Text(" I am Jack "),
],
),
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(" hello world "),
Text(" I am Jack "),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
textDirection: TextDirection.rtl,
children: <Widget>[
Text(" hello world "),
Text(" I am Jack "),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
verticalDirection: VerticalDirection.up,
children: <Widget>[
Text(" hello world ", style: TextStyle(fontSize: 30.0),),
Text(" I am Jack "),
],
),
],
);
```
運行結果:

解釋:第一個Row很簡單,默認為居中對齊;第二個Row,由于mainAxisSize值為`MainAxisSize.min`,Row的寬度等于兩個Text的寬度和,所以對齊是無意義的,所以會從左往右顯示;第三個Row設置textDirection值為`TextDirection.rtl`,所以子widget會從右向左的順序排列,而此時`MainAxisAlignment.end`表示左對齊,所以最終顯示結果就是圖中第三行的樣子;第四個Row測試的是縱軸的對齊方式,由于兩個子Text字體不一樣,所以其高度也不同,我們指定了verticalDirection值為`VerticalDirection.up`,即從低向頂排列,而此時crossAxisAlignment值為CrossAxisAlignment.start表示底對齊。
### Column
Column可以在垂直方向排列其子widget。參數和Row一樣,不同的是布局方向為垂直,主軸縱軸正好相反,讀者可類比Row來理解,在此不再贅述。
### 特殊情況
如果Row里面嵌套Row,或者Column里面再嵌套Column,那么只有對最外面的Row或Column會占用盡可能大的空間,里面Row或Column所占用的空間為實際大小,下面以Column為例說明:
```
Container(
color: Colors.green,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max, //有效,外層Colum高度為整個屏幕
children: <Widget>[
Container(
color: Colors.red,
child: Column(
mainAxisSize: MainAxisSize.max,//無效,內層Colum高度為實際高度
children: <Widget>[
Text("hello world "),
Text("I am Jack "),
],
),
)
],
),
),
);
```
運行結果:

如果要讓里面的Colum占滿外部Colum,可以使用Expanded widget:
```
Expanded(
child: Container(
color: Colors.red,
child: Column(
mainAxisAlignment: MainAxisAlignment.center, //垂直方向居中對齊
children: <Widget>[
Text("hello world "),
Text("I am Jack "),
],
),
),
)
```
運行效果:

我們將在介紹彈性布局時詳細介紹Expanded。
- 緣起
- 起步
- 移動開發技術簡介
- Flutter簡介
- 搭建Flutter開發環境
- 常見配置問題
- Dart語言簡介
- 第一個Flutter應用
- 計數器示例
- 路由管理
- 包管理
- 資源管理
- 調試Flutter APP
- Dart線程模型及異常捕獲
- 基礎Widgets
- Widget簡介
- 文本、字體樣式
- 按鈕
- 圖片和Icon
- 單選框和復選框
- 輸入框和表單
- 布局類Widgets
- 布局類Widgets簡介
- 線性布局Row、Column
- 彈性布局Flex
- 流式布局Wrap、Flow
- 層疊布局Stack、Positioned
- 容器類Widgets
- Padding
- 布局限制類容器ConstrainedBox、SizeBox
- 裝飾容器DecoratedBox
- 變換Transform
- Container容器
- Scaffold、TabBar、底部導航
- 可滾動Widgets
- 可滾動Widgets簡介
- SingleChildScrollView
- ListView
- GridView
- CustomScrollView
- 滾動監聽及控制ScrollController
- 功能型Widgets
- 導航返回攔截-WillPopScope
- 數據共享-InheritedWidget
- 主題-Theme
- 事件處理與通知
- 原始指針事件處理
- 手勢識別
- 全局事件總線
- 通知Notification
- 動畫
- Flutter動畫簡介
- 動畫結構
- 自定義路由過渡動畫
- Hero動畫
- 交錯動畫
- 自定義Widget
- 自定義Widget方法簡介
- 通過組合現有Widget實現
- 實例:TurnBox
- CustomPaint與Canvas
- 實例:圓形漸變進度條(自繪)
- 文件操作與網絡請求
- 文件操作
- Http請求-HttpClient
- Http請求-Dio package
- 實例:Http分塊下載
- WebSocket
- 使用Socket API
- Json轉Model
- 包與插件
- 開發package
- 插件開發:平臺通道簡介
- 插件開發:實現Android端API
- 插件開發:實現IOS端API
- 系統能力調用
- 國際化
- 讓App支持多語言
- 實現Localizations
- 使用Intl包
- Flutter核心原理
- Flutter UI系統
- Element和BuildContext
- RenderObject與RenderBox
- Flutter從啟動到顯示