跟隨《Flutter實(shí)戰(zhàn)·第二版》學(xué)習(xí),建議直接看原書
所謂線性布局,即指沿水平或垂直方向排列子組件。Flutter 中通過Row和Column來實(shí)現(xiàn)線性布局,類似于Android 中的LinearLayout控件。Row和Column都繼承自Flex咆霜,我們將在彈性布局一節(jié)中詳細(xì)介紹Flex
主軸和縱軸
對于線性布局,有主軸和縱軸之分嘶朱,如果布局是沿水平方向蛾坯,那么主軸就是指水平方向,而縱軸即垂直方向疏遏;如果布局沿垂直方向偿衰,那么主軸就是指垂直方向挂疆,而縱軸就是水平方向。在線性布局中下翎,有兩個(gè)定義對齊方式的枚舉類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:表示水平方向子組件的布局順序(是從左往右還是從右往左)胆萧,默認(rèn)為系統(tǒng)當(dāng)前Locale環(huán)境的文本方向(如中文、英語都是從左往右俐东,而阿拉伯語是從右往左)跌穗。
- mainAxisSize:表示Row在主軸(水平)方向占用的空間,默認(rèn)是MainAxisSize.max虏辫,表示盡可能多的占用水平方向的空間蚌吸,此時(shí)無論子 widgets 實(shí)際占用多少水平空間,Row的寬度始終等于水平方向的最大寬度砌庄;而MainAxisSize.min表示盡可能少的占用水平空間羹唠,當(dāng)子組件沒有占滿水平剩余空間,則Row的實(shí)際寬度等于所有子組件占用的的水平空間娄昆;
- mainAxisAlignment:表示子組件在Row所占用的水平空間內(nèi)對齊方式佩微,如果mainAxisSize值為MainAxisSize.min,則此屬性無意義萌焰,因?yàn)樽咏M件的寬度等于Row的寬度哺眯。只有當(dāng)mainAxisSize的值為MainAxisSize.max時(shí),此屬性才有意義扒俯,MainAxisAlignment.start表示沿textDirection的初始方向?qū)R奶卓,如textDirection取值為TextDirection.ltr時(shí),則MainAxisAlignment.start表示左對齊撼玄,textDirection取值為TextDirection.rtl時(shí)表示從右對齊夺姑。而MainAxisAlignment.end和MainAxisAlignment.start正好相反;MainAxisAlignment.center表示居中對齊互纯。讀者可以這么理解:textDirection是mainAxisAlignment的參考系瑟幕。
- verticalDirection:表示Row縱軸(垂直)的對齊方向磕蒲,默認(rèn)是VerticalDirection.down留潦,表示從上到下。
- crossAxisAlignment:表示子組件在縱軸方向的對齊方式辣往,Row的高度等于子組件中最高的子元素高度兔院,它的取值和MainAxisAlignment一樣(包含start、end站削、 center三個(gè)值)坊萝,不同的是crossAxisAlignment的參考系是verticalDirection,即verticalDirection值為VerticalDirection.down時(shí)crossAxisAlignment.start指頂部對齊,verticalDirection值為VerticalDirection.up時(shí)十偶,crossAxisAlignment.start指底部對齊菩鲜;而crossAxisAlignment.end和crossAxisAlignment.start正好相反;
- children :子組件數(shù)組惦积。
示例
Column(
// 測試Row對齊方式 排除Column默認(rèn)居中對齊的干擾
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(" Hello World "),
Text(" I'm Jack "),
],
),
Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(" Hello World "),
Text(" I'm Jack "),
],
),
Row(
mainAxisAlignment: MainAxisAlignment.end,
textDirection: TextDirection.rtl,
children: <Widget>[
Text(" Hello World "),
Text(" I'm Jack "),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
verticalDirection: VerticalDirection.up,
children: <Widget>[
Text(" Hello World ", style: TextStyle(fontSize: 30)),
Text(" I'm Jack "),
],
),
],
)
解釋:第一個(gè)Row很簡單接校,默認(rèn)為居中對齊;第二個(gè)Row狮崩,由于mainAxisSize值為MainAxisSize.min蛛勉,Row的寬度等于兩個(gè)Text的寬度和,所以對齊是無意義的睦柴,所以會從左往右顯示诽凌;第三個(gè)Row設(shè)置textDirection值為TextDirection.rtl,所以子組件會從右向左的順序排列坦敌,而此時(shí)MainAxisAlignment.end表示左對齊侣诵,所以最終顯示結(jié)果就是圖中第三行的樣子;第四個(gè) Row 測試的是縱軸的對齊方式恬试,由于兩個(gè)子 Text 字體不一樣窝趣,所以其高度也不同,我們指定了verticalDirection值為VerticalDirection.up训柴,即從低向頂排列哑舒,而此時(shí)crossAxisAlignment值為CrossAxisAlignment.start表示底對齊
Column
Column可以在垂直方向排列其子組件。參數(shù)和Row一樣幻馁,不同的是布局方向?yàn)榇怪毕赐遥鬏S縱軸正好相反,讀者可類比Row來理解仗嗦,下面看一個(gè)例子:
Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text("hi"),
Text("world"),
],
);
解釋:
- 由于我們沒有指定Column的mainAxisSize膘滨,所以使用默認(rèn)值MainAxisSize.max,則Column會在垂直方向占用盡可能多的空間稀拐,此例中會占滿整個(gè)屏幕高度
- 由于我們指定了 crossAxisAlignment 屬性為CrossAxisAlignment.center火邓,那么子項(xiàng)在Column縱軸方向(此時(shí)為水平方向)會居中對齊。注意德撬,在水平方向?qū)R是有邊界的铲咨,總寬度為Column占用空間的實(shí)際寬度,而實(shí)際的寬度取決于子項(xiàng)中寬度最大的Widget蜓洪。在本例中纤勒,Column有兩個(gè)子Widget,而顯示“world”的Text寬度最大隆檀,所以Column的實(shí)際寬度則為Text("world") 的寬度摇天,所以居中對齊后Text("hi")會顯示在Text("world")的中間部分
實(shí)際上粹湃,Row和Column都只會在主軸方向占用盡可能大的空間,而縱軸的長度則取決于他們最大子元素的長度泉坐。如果我們想讓本例中的兩個(gè)文本控件在整個(gè)手機(jī)屏幕中間對齊为鳄,我們有兩種方法:
- 將Column的寬度指定為屏幕寬度;這很簡單腕让,我們可以通過ConstrainedBox或SizedBox(我們將在后面章節(jié)中專門介紹這兩個(gè)Widget)來強(qiáng)制更改寬度限制济赎,例如:
ConstrainedBox(
constraints: BoxConstraints(minWidth: double.infinity),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Text("hi"),
Text("world"),
],
),
),
特殊情況
如果Row里面嵌套Row,或者Column里面再嵌套Column记某,那么只有最外面的Row或Column會占用盡可能大的空間司训,里面Row或Column所占用的空間為實(shí)際大小,下面以Column為例說明:
Container(
color: Colors.green,
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max, //有效 外層Column高度為整個(gè)屏幕
children: <Widget>[
Container(
color: Colors.red,
child: Column(
mainAxisSize: MainAxisSize.max, // 無效 內(nèi)層Column高度為實(shí)際高度
children: <Widget>[
Text(" hello world "),
Text("I am Jack"),
],
),
),
],
),
),
),
如果要讓里面的Column占滿外部Column液南,可以使用Expanded 組件:
Container(
color: Colors.green,
child: Padding(
padding: EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max, //有效 外層Column高度為整個(gè)屏幕
children: <Widget>[
Expanded(
child: Container(
color: Colors.red,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(" hello world "),
Text("I am Jack"),
],
),
),
),
],
),
),
),