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

2021-03-08 09:56 更新

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

#主軸和縱軸

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

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

#示例

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

Column(
  //測(cè)試Row對(duì)齊方式,排除Column默認(rèn)居中對(duì)齊的干擾
  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 "),
      ],
    ),
  ],
);

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

圖4-1

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

#Column

Column可以在垂直方向排列其子組件。參數(shù)和Row一樣,不同的是布局方向?yàn)榇怪保鬏S縱軸正好相反,讀者可類比Row來理解,下面看一個(gè)例子:

import 'package:flutter/material.dart';


class CenterColumnRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: <Widget>[
        Text("hi"),
        Text("world"),
      ],
    );
  }
}

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

圖4-2示例

解釋:

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

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

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

  ConstrainedBox(
    constraints: BoxConstraints(minWidth: double.infinity), 
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.center,
      children: <Widget>[
        Text("hi"),
        Text("world"),
      ],
    ),
  );

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

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

#特殊情況

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

Container(
  color: Colors.green,
  child: Padding(
    padding: const EdgeInsets.all(16.0),
    child: Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      mainAxisSize: MainAxisSize.max, //有效,外層Colum高度為整個(gè)屏幕
      children: <Widget>[
        Container(
          color: Colors.red,
          child: Column(
            mainAxisSize: MainAxisSize.max,//無效,內(nèi)層Colum高度為實(shí)際高度  
            children: <Widget>[
              Text("hello world "),
              Text("I am Jack "),
            ],
          ),
        )
      ],
    ),
  ),
);

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

圖4-3

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

Expanded( 
  child: Container(
    color: Colors.red,
    child: Column(
      mainAxisAlignment: MainAxisAlignment.center, //垂直方向居中對(duì)齊
      children: <Widget>[
        Text("hello world "),
        Text("I am Jack "),
      ],
    ),
  ),
)

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

圖4-4

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

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

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)