所謂線性佈局,即指沿水平或垂直方向排布子組件。Flutter中通過Row和Column來實現線性佈局,類似於Android中的LinearLayout控件。
對於線性佈局,有主軸和縱軸之分,如果佈局是沿水平方向,那麼主軸就是指水平方向,而縱軸即垂直方向;如果佈局沿垂直方向,那麼主軸就是指垂直方向,而縱軸就是水平方向。在線性佈局中,有兩個定義對齊方式的枚舉類MainAxisAlignment和CrossAxisAlignment,分別代表主軸對齊和縱軸對齊。這裏我們可以參考web中的Flex佈局。
Row
Row可以在水平方向排列其子widget,其定義如下:
class Row extends Flex {
/// Creates a horizontal array of children.
///
/// The [direction], [mainAxisAlignment], [mainAxisSize],
/// [crossAxisAlignment], and [verticalDirection] arguments must not be null.
/// If [crossAxisAlignment] is [CrossAxisAlignment.baseline], then
/// [textBaseline] must not be null.
///
/// The [textDirection] argument defaults to the ambient [Directionality], if
/// any. If there is no ambient directionality, and a text direction is going
/// to be necessary to determine the layout order (which is always the case
/// unless the row has no children or only one child) or to disambiguate
/// `start` or `end` values for the [mainAxisAlignment], the [textDirection]
/// must not be null.
Row({
Key key,
MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
MainAxisSize mainAxisSize = MainAxisSize.max,
CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
TextDirection textDirection,
VerticalDirection verticalDirection = VerticalDirection.down,
TextBaseline textBaseline,
List<Widget> children = const <Widget>[],
}) : super(
children: children,
key: key,
direction: Axis.horizontal,
mainAxisAlignment: mainAxisAlignment,
mainAxisSize: mainAxisSize,
crossAxisAlignment: crossAxisAlignment,
textDirection: textDirection,
verticalDirection: verticalDirection,
textBaseline: textBaseline,
);
}
textDirection:表示水平方向子組件的佈局順序(是從左往右(ltr)還是從右往左(rtl)),默認爲系統當前Locale環境的文本方向(如中文、英語都是從左往右,而阿拉伯語是從右往左)。
修改佈局順序爲從右往左:
mainAxisSize:表示Row在主軸(水平)方向佔用的空間,默認是MainAxisSize.max,表示儘可能多的佔用水平方向的空間,此時無論子widgets實際佔用多少水平空間,Row的寬度始終等於水平方向的最大寬度。而MainAxisSize.min表示儘可能少的佔用水平空間,當子組件沒有佔滿水平剩餘空間,則Row的實際寬度等於所有子組件佔用的的水平空間。
看個例子:
運行效果:
這裏打開了佈局網格,以便於大家直觀的看到widget所佔用的空間。
此時我們修改mainAxisSize爲MainAxisSize.min:
mainAxisSize: MainAxisSize.min,
運行效果:
注意:如果子widgets實際佔用多少水平空間超過了水平方向的最大寬度,那麼會報錯。
在開發模式下我們會得到下面的結果:
mainAxisAlignment:表示子組件在Row所佔用的水平空間內對齊方式。
mainAxisSize值爲MainAxisSize.min,則此屬性無意義,因爲子組件的寬度等於Row的寬度。
mainAxisSize的值爲MainAxisSize.max時,此屬性纔有意義,MainAxisAlignment.start表示沿textDirection的初始方向對齊,如textDirection取值爲TextDirection.ltr時,則MainAxisAlignment.start表示左對齊,textDirection取值爲TextDirection.rtl時表示從右對齊。而MainAxisAlignment.end和MainAxisAlignment.start正好相反;MainAxisAlignment.center表示居中對齊。
示例:
可選值如下:
start:將children放置在主軸的起點
center:將children放置在主軸的中心
end:將children放置在主軸的末尾
spaceEvenly:將主軸方向上的空白區域均分,使得children之間的空白區域相等,包括首尾child
spaceAround:將主軸方向上的空白區域均分,使得children之間的空白區域相等,但是首尾child的空白區域爲1/2
spaceBetween:將主軸方向上的空白區域均分,使得children之間的空白區域相等,首尾child都靠近首尾,沒有間隙
其中spaceAround、spaceBetween以及spaceEvenly的區別,就是對待首尾child的方式。其距離首尾的距離分別是空白區域的1/2、0、1。
verticalDirection:表示Row縱軸(垂直)的對齊方向,默認VerticalDirection.down,表示從上到下。可選值爲VerticalDirection.down 和VerticalDirection.up。在Row模式下需要配合crossAxisAlignment使用。默認是VerticalDirection.down,表示從上到下。
如下例:
運行效果:
將參數修改爲down:
crossAxisAlignment:表示子組件在縱軸方向的對齊方式。Row的高度等於子組件中最高的子元素高度,它的取值和MainAxisAlignment一樣(包含start、end、 center三個值),不同的是crossAxisAlignment的參考系是verticalDirection。
可選值如下:
/**
* start:把 children 放到交叉軸的頭部
*
* center:把 children 放到交叉軸的中間
*
* end: 把 children 放到交叉軸的尾部
*
* stretch:讓children填滿交叉軸方向
*
* baseline:在交叉軸方向,使得children的baseline對齊,textBaseline 不能爲 null
* */
start:
end:
strech:
center:
Column
Column可以在垂直方向排列其子組件。參數和Row一樣,不同的是佈局方向爲垂直,主軸縱軸正好相反.
來看個簡單的例子:
運行效果:
由於我們沒有指定Column的mainAxisSize,所以使用默認值MainAxisSize.max,則Column會在垂直方向佔用儘可能多的空間,此例中爲屏幕高度。
由於我們指定了 crossAxisAlignment 屬性爲CrossAxisAlignment.center,那麼子項在Column縱軸方向(此時爲水平方向)會居中對齊。注意,在水平方向對齊是有邊界的,總寬度爲Column佔用空間的實際寬度,而實際的寬度取決於子項中寬度最大的Widget。
實際上不管是Row還是Column都只會在主軸方向佔據最大空間,而縱軸的長度則取決於他們最大子元素的長度。
這裏需要注意的一點是:Row裏面嵌套Row,或者Column裏面再嵌套Column,那麼只有對最外面的Row或Column會佔用盡可能大的空間,裏面Row或Column所佔用的空間爲實際大小。
運行效果: