Flutter實戰(zhàn) 線性布局(ROW和Column)

2021-03-08 09:56 更新

所謂線性布局,即指沿水平或垂直方向排布子組件。Flutter 中通過RowColumn來實現(xiàn)線性布局,類似于 Android 中的LinearLayout控件。RowColumn都繼承自Flex,我們將在彈性布局一節(jié)中詳細(xì)介紹Flex。

#主軸和縱軸

對于線性布局,有主軸和縱軸之分,如果布局是沿水平方向,那么主軸就是指水平方向,而縱軸即垂直方向;如果布局沿垂直方向,那么主軸就是指垂直方向,而縱軸就是水平方向。在線性布局中,有兩個定義對齊方式的枚舉類MainAxisAlignmentCrossAxisAlignment,分別代表主軸對齊和縱軸對齊。

#Row

Row 可以在水平方向排列其子 widget。定義如下:

  1. Row({
  2. ...
  3. TextDirection textDirection,
  4. MainAxisSize mainAxisSize = MainAxisSize.max,
  5. MainAxisAlignment mainAxisAlignment = MainAxisAlignment.start,
  6. VerticalDirection verticalDirection = VerticalDirection.down,
  7. CrossAxisAlignment crossAxisAlignment = CrossAxisAlignment.center,
  8. List<Widget> children = const <Widget>[],
  9. })

  • textDirection:表示水平方向子組件的布局順序(是從左往右還是從右往左),默認(rèn)為系統(tǒng)當(dāng)前Locale環(huán)境的文本方向(如中文、英語都是從左往右,而阿拉伯語是從右往左)。
  • mainAxisSize:表示Row在主軸(水平)方向占用的空間,默認(rèn)是MainAxisSize.max,表示盡可能多的占用水平方向的空間,此時無論子widgets實際占用多少水平空間,Row的寬度始終等于水平方向的最大寬度;而MainAxisSize.min表示盡可能少的占用水平空間,當(dāng)子組件沒有占滿水平剩余空間,則Row的實際寬度等于所有子組件占用的的水平空間;
  • mainAxisAlignment:表示子組件在Row所占用的水平空間內(nèi)對齊方式,如果mainAxisSize值為MainAxisSize.min,則此屬性無意義,因為子組件的寬度等于Row的寬度。只有當(dāng)mainAxisSize的值為MainAxisSize.max時,此屬性才有意義,MainAxisAlignment.start表示沿textDirection的初始方向?qū)R,如textDirection取值為TextDirection.ltr時,則MainAxisAlignment.start表示左對齊,textDirection取值為TextDirection.rtl時表示從右對齊。而MainAxisAlignment.endMainAxisAlignment.start正好相反;MainAxisAlignment.center表示居中對齊。讀者可以這么理解:textDirectionmainAxisAlignment的參考系。
  • verticalDirection:表示Row縱軸(垂直)的對齊方向,默認(rèn)是VerticalDirection.down,表示從上到下。
  • crossAxisAlignment:表示子組件在縱軸方向的對齊方式,Row的高度等于子組件中最高的子元素高度,它的取值和MainAxisAlignment一樣(包含start、end、 center三個值),不同的是crossAxisAlignment的參考系是verticalDirection,即verticalDirection值為VerticalDirection.downcrossAxisAlignment.start指頂部對齊,verticalDirection值為VerticalDirection.up時,crossAxisAlignment.start指底部對齊;而crossAxisAlignment.endcrossAxisAlignment.start正好相反;
  • children :子組件數(shù)組。

#示例

請閱讀下面代碼,先想象一下運(yùn)行的結(jié)果:

  1. Column(
  2. //測試Row對齊方式,排除Column默認(rèn)居中對齊的干擾
  3. crossAxisAlignment: CrossAxisAlignment.start,
  4. children: <Widget>[
  5. Row(
  6. mainAxisAlignment: MainAxisAlignment.center,
  7. children: <Widget>[
  8. Text(" hello world "),
  9. Text(" I am Jack "),
  10. ],
  11. ),
  12. Row(
  13. mainAxisSize: MainAxisSize.min,
  14. mainAxisAlignment: MainAxisAlignment.center,
  15. children: <Widget>[
  16. Text(" hello world "),
  17. Text(" I am Jack "),
  18. ],
  19. ),
  20. Row(
  21. mainAxisAlignment: MainAxisAlignment.end,
  22. textDirection: TextDirection.rtl,
  23. children: <Widget>[
  24. Text(" hello world "),
  25. Text(" I am Jack "),
  26. ],
  27. ),
  28. Row(
  29. crossAxisAlignment: CrossAxisAlignment.start,
  30. verticalDirection: VerticalDirection.up,
  31. children: <Widget>[
  32. Text(" hello world ", style: TextStyle(fontSize: 30.0),),
  33. Text(" I am Jack "),
  34. ],
  35. ),
  36. ],
  37. );

實際運(yùn)行結(jié)果如圖4-1所示:

圖4-1

解釋:第一個Row很簡單,默認(rèn)為居中對齊;第二個Row,由于mainAxisSize值為MainAxisSize.min,Row的寬度等于兩個Text的寬度和,所以對齊是無意義的,所以會從左往右顯示;第三個Row設(shè)置textDirection值為TextDirection.rtl,所以子組件會從右向左的順序排列,而此時MainAxisAlignment.end表示左對齊,所以最終顯示結(jié)果就是圖中第三行的樣子;第四個Row測試的是縱軸的對齊方式,由于兩個子Text字體不一樣,所以其高度也不同,我們指定了verticalDirection值為VerticalDirection.up,即從低向頂排列,而此時crossAxisAlignment值為CrossAxisAlignment.start表示底對齊。

#Column

Column可以在垂直方向排列其子組件。參數(shù)和Row一樣,不同的是布局方向為垂直,主軸縱軸正好相反,讀者可類比Row來理解,下面看一個例子:

  1. import 'package:flutter/material.dart';
  2. class CenterColumnRoute extends StatelessWidget {
  3. @override
  4. Widget build(BuildContext context) {
  5. return Column(
  6. crossAxisAlignment: CrossAxisAlignment.center,
  7. children: <Widget>[
  8. Text("hi"),
  9. Text("world"),
  10. ],
  11. );
  12. }
  13. }

運(yùn)行效果如圖4-2所示:

圖4-2示例

解釋:

  • 由于我們沒有指定ColumnmainAxisSize,所以使用默認(rèn)值MainAxisSize.max,則Column會在垂直方向占用盡可能多的空間,此例中為屏幕高度。
  • 由于我們指定了 crossAxisAlignment 屬性為CrossAxisAlignment.center,那么子項在Column縱軸方向(此時為水平方向)會居中對齊。注意,在水平方向?qū)R是有邊界的,總寬度為Column占用空間的實際寬度,而實際的寬度取決于子項中寬度最大的 Widget。在本例中,Column有兩個子 Widget,而顯示“world”的Text寬度最大,所以Column的實際寬度則為Text("world") 的寬度,所以居中對齊后Text("hi")會顯示在Text("world")的中間部分。

實際上,RowColumn都只會在主軸方向占用盡可能大的空間,而縱軸的長度則取決于他們最大子元素的長度。如果我們想讓本例中的兩個文本控件在整個手機(jī)屏幕中間對齊,我們有兩種方法:

  • Column的寬度指定為屏幕寬度;這很簡單,我們可以通過ConstrainedBoxSizedBox(我們將在后面章節(jié)中專門介紹這兩個 Widget)來強(qiáng)制更改寬度限制,例如:

  1. ConstrainedBox(
  2. constraints: BoxConstraints(minWidth: double.infinity),
  3. child: Column(
  4. crossAxisAlignment: CrossAxisAlignment.center,
  5. children: <Widget>[
  6. Text("hi"),
  7. Text("world"),
  8. ],
  9. ),
  10. );

minWidth設(shè)為double.infinity,可以使寬度占用盡可能多的空間。

  • 使用Center Widget;我們將在后面章節(jié)中介紹。

#特殊情況

如果Row里面嵌套Row,或者Column里面再嵌套Column,那么只有最外面的RowColumn會占用盡可能大的空間,里面RowColumn所占用的空間為實際大小,下面以Column為例說明:

  1. Container(
  2. color: Colors.green,
  3. child: Padding(
  4. padding: const EdgeInsets.all(16.0),
  5. child: Column(
  6. crossAxisAlignment: CrossAxisAlignment.start,
  7. mainAxisSize: MainAxisSize.max, //有效,外層Colum高度為整個屏幕
  8. children: <Widget>[
  9. Container(
  10. color: Colors.red,
  11. child: Column(
  12. mainAxisSize: MainAxisSize.max,//無效,內(nèi)層Colum高度為實際高度
  13. children: <Widget>[
  14. Text("hello world "),
  15. Text("I am Jack "),
  16. ],
  17. ),
  18. )
  19. ],
  20. ),
  21. ),
  22. );

運(yùn)行效果如圖4-3所示:

圖4-3

如果要讓里面的Column占滿外部Column,可以使用Expanded 組件:

  1. Expanded(
  2. child: Container(
  3. color: Colors.red,
  4. child: Column(
  5. mainAxisAlignment: MainAxisAlignment.center, //垂直方向居中對齊
  6. children: <Widget>[
  7. Text("hello world "),
  8. Text("I am Jack "),
  9. ],
  10. ),
  11. ),
  12. )

運(yùn)行效果如圖4-4所示:

圖4-4

我們將在介紹彈性布局時詳細(xì)介紹 Expanded。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號