Flutter Widget(3):多節點Widget

1.Row

線性布局,將children排成一行,主軸為水平方向,交叉軸為垂直方向。

  • textDirection:表示水平方向子widget的布局順序是從左往右還是從右往左。
  • mainAxisSize:主軸方向的占用空間。默認是MainAxisSize.max,表示盡可能多的占用水平方向的空間,此時無論子widgets實際占用多少水平空間,Row的寬度始終等于水平方向的最大寬度;而MainAxisSize.min表示盡可能少的占用水平空間,當子widgets沒有占滿水平剩余空間,則Row的實際寬度等于所有子widgets占用的的水平空間;
  • mainAxisAlignment:主軸對齊方式,如果mainAxisSize值為MainAxisSize.min ,則此屬性無意義,因為子widgets的寬度等于Row的寬度。只有當mainAxisSize的值為MainAxisSize.max時,此屬性才有意義。textDirection是mainAxisAlignment的參考系,textDirection取值為TextDirection.ltr時,則MainAxisAlignment.start表示左對齊,textDirection取值為TextDirection.rtl時表示從右對齊。
  • crossAxisAlignment:交叉軸對齊方式,Row的高度等于子Widgets中最高的子元素高度。crossAxisAlignment的參考系是verticalDirection,即verticalDirection值為VerticalDirection.down時crossAxisAlignment.start指頂部對齊,verticalDirection值為VerticalDirection.up時,crossAxisAlignment.start指底部對齊;而crossAxisAlignment.end和crossAxisAlignment.start正好相反;
  • children :子widget數組

2.Column

Column可以在垂直方向排列其子widget。參數和Row一樣,不同的是布局方向為垂直,主軸縱軸正好相反

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

3.Stack

可以允許其子widget簡單的堆疊在一起,相當于Android中的FrameLayout,

  • alignment:此參數決定如何去對齊沒有定位(沒有使用Positioned)或部分定位的子widget。所謂部分定位,在這里特指沒有在某一個軸上定位:left、right為橫軸,top、bottom為縱軸,只要包含某個軸上的一個定位屬性就算在該軸上有定位。
  • textDirection:決定alignment對齊的參考系即:textDirection的值為TextDirection.ltr,則alignment的start代表左,end代表右;textDirection的值為TextDirection.rtl,則alignment的start代表右,end代表左。
  • fit:此參數用于決定沒有定位的子widget如何去適應Stack的大小。StackFit.loose表示使用子widget的大小,StackFit.expand表示擴伸到Stack的大小,passthrough不改變子widget的約束條件。
  • overflow:此屬性決定如何顯示超出Stack顯示空間的子widget,值為Overflow.clip時,超出部分會被剪裁(隱藏),值為Overflow.visible 時則不會。

Positioned

const Positioned({
  Key key,
  this.left, 
  this.top,
  this.right,
  this.bottom,
  this.width,
  this.height,
  @required Widget child,
})

left、top 、right、 bottom分別代表離Stack左、上、右、底四邊的距離。width和height用于指定定位元素的寬度和高度,注意,此處的width、height 和其它地方的意義稍微有點區別,此處用于配合left、top 、right、 bottom來定位widget,舉個例子,在水平方向時,你只能指定left、right、width三個屬性中的兩個,如指定left和width后,right會自動算出(left+width),如果同時指定三個屬性則會報錯,垂直方向同理。

4.IndexedStack

IndexedStack繼承自Stack,它的作用是顯示第index個child,其他child都是不可見的。所以IndexedStack的尺寸永遠是跟最大的子節點尺寸一致。

5.Wrap

子Widget超出屏幕范圍會自動換行,Wrap的很多屬性在Row(包括Flex和Column)中也有,如direction、crossAxisAlignment、textDirection、verticalDirection等

  • direction:主軸(mainAxis)的方向,默認為水平。
  • alignment:主軸方向上的對齊方式,默認為start。
  • spacing:主軸方向子widget的間距
  • runSpacing:縱軸方向的間距
  • runAlignment:縱軸方向的對齊方式

6.Flow

一個實現流式布局算法的widget,使用比較復雜,一般多實用Wrap

7.Table

為其子widget使用表格布局算法的widget,

Table({
  Key key,
  this.children = const <TableRow>[],
  this.columnWidths,
  this.defaultColumnWidth = const FlexColumnWidth(1.0),
  this.textDirection,
  this.border,
  this.defaultVerticalAlignment = TableCellVerticalAlignment.top,
  this.textBaseline,
})
  • columnWidths:設置每一列的寬度。
  • defaultColumnWidth:默認的每一列寬度值,默認情況下均分。
  • textDirection:文字方向
  • border:表格邊框。
  • defaultVerticalAlignment:每一個cell的垂直方向的alignment。
    總共包含5種:
    top:被放置在的頂部;
    middle:垂直居中;
    bottom:放置在底部;
    baseline:文本baseline對齊;
    fill:充滿整個cell。
  • textBaseline:defaultVerticalAlignment為baseline的時候,會用到這個屬性。

8.ListView

ListView是最常用的可滾動widget,它可以沿一個方向線性排布所有子widget。

  • itemExtent:該參數如果不為null,則會強制children的"長度"為itemExtent的值;這里的"長度"是指滾動方向上子widget的長度,即如果滾動方向是垂直方向,則itemExtent代表子widget的高度,如果滾動方向為水平方向,則itemExtent代表子widget的長度。在ListView中,指定itemExtent比讓子widget自己決定自身長度會更高效,這是因為指定itemExtent后,滾動系統可以提前知道列表的長度,而不是總是動態去計算,尤其是在滾動位置頻繁變化時(滾動系統需要頻繁去計算列表高度)。
  • shrinkWrap:該屬性表示是否根據子widget的總長度來設置ListView的長度,默認值為false 。默認情況下,ListView的會在滾動方向盡可能多的占用空間。當ListView在一個無邊界(滾動方向上)的容器中時,shrinkWrap必須為true。
  • addAutomaticKeepAlives:該屬性表示是否將列表項(子widget)包裹在AutomaticKeepAlive widget中;典型地,在一個懶加載列表中,如果將列表項包裹在AutomaticKeepAlive中,在該列表項滑出視口時該列表項不會被GC,它會使用KeepAliveNotification來保存其狀態。如果列表項自己維護其KeepAlive狀態,那么此參數必須置為false。
  • addRepaintBoundaries:該屬性表示是否將列表項(子widget)包裹在RepaintBoundary中。當可滾動widget滾動時,將列表項包裹在RepaintBoundary中可以避免列表項重繪,但是當列表項重繪的開銷非常小(如一個顏色塊,或者一個較短的文本)時,不添加RepaintBoundary反而會更高效。和addAutomaticKeepAlive一樣,如果列表項自己維護其KeepAlive狀態,那么此參數必須置為false。

默認構造函數

ListView(
  shrinkWrap: true,
  padding: EdgeInsets.all(20.0),
  children: <Widget>[
    Text('I\'m dedicating every day to you'),
    Text('Domestic life was never quite my style'),
    Text('When you smile, you knock me out, I fall apart'),
    Text('And I thought I was so smart'),
  ],
)

ListView.builder

ListView.builder(
  itemCount: 1000,
  itemBuilder: (context, index) {
    return ListTile(
      title: Text("$index"),
    );
  },
)

ListView.separated

class ListView3 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    //下劃線widget預定義以供復用。  
    Widget divider1=Divider(color: Colors.blue,);
    Widget divider2=Divider(color: Colors.green);
    return ListView.separated(
        itemCount: 100,
        //列表項構造器
        itemBuilder: (BuildContext context, int index) {
          return ListTile(title: Text("$index"));
        },
        //分割器構造器
        separatorBuilder: (BuildContext context, int index) {
          return index%2==0?divider1:divider2;
        },
    );
  }
}

9.GridView

一個滾動的多列列表

默認構造函數

GridView({
  Axis scrollDirection = Axis.vertical,
  bool reverse = false,
  ScrollController controller,
  bool primary,
  ScrollPhysics physics,
  bool shrinkWrap = false,
  EdgeInsetsGeometry padding,
  @required SliverGridDelegate gridDelegate, //控制子widget layout的委托
  bool addAutomaticKeepAlives = true,
  bool addRepaintBoundaries = true,
  double cacheExtent,
  List<Widget> children = const <Widget>[],
})
  • scrollDirection:滾動的方向,有垂直和水平兩種,默認為垂直方向(Axis.vertical)。
  • reverse:默認是從上或者左向下或者右滾動的,這個屬性控制是否反向,默認值為false,不反向滾動。
  • controller:控制child滾動時候的位置。
  • primary:是否是與父節點的PrimaryScrollController所關聯的主滾動視圖。
  • physics:滾動的視圖如何響應用戶的輸入。
  • shrinkWrap:滾動方向的滾動視圖內容是否應該由正在查看的內容所決定。
  • padding:四周的空白區域。
  • cacheExtent:緩存區域。
  • gridDelegate:控制GridView中子節點布局的delegate。

gridDelegate參數,類型是SliverGridDelegate,它的作用是控制GridView子widget如何排列(layout),SliverGridDelegate是一個抽象類,定義了GridView Layout相關接口,子類需要通過實現它們來實現具體的布局算法,Flutter中提供了兩個SliverGridDelegate的子類SliverGridDelegateWithFixedCrossAxisCount和SliverGridDelegateWithMaxCrossAxisExtent

SliverGridDelegateWithFixedCrossAxisCount

該類通過確定橫軸子widget的數量和寬高比從而確定了子widget的最大限時空間

SliverGridDelegateWithFixedCrossAxisCount({
  @required double crossAxisCount, 
  double mainAxisSpacing = 0.0,
  double crossAxisSpacing = 0.0,
  double childAspectRatio = 1.0,
})
  • crossAxisCount:橫軸子元素的數量。此屬性值確定后子元素在橫軸的長度就確定了,即ViewPort橫軸長度/crossAxisCount。
  • mainAxisSpacing:主軸方向的間距。
  • crossAxisSpacing:橫軸方向子元素的間距。
  • childAspectRatio:子元素在橫軸長度和主軸長度的比例。由于crossAxisCount指定后子元素橫軸長度就確定了,然后通過此參數值就可以確定子元素在主軸的長度。

SliverGridDelegateWithMaxCrossAxisExtent

該類通過確定子widget在交叉軸的最大長度和寬高比從而確定了子widget的最大限時空間

SliverGridDelegateWithMaxCrossAxisExtent({
  double maxCrossAxisExtent,
  double mainAxisSpacing = 0.0,
  double crossAxisSpacing = 0.0,
  double childAspectRatio = 1.0,
})
  • maxCrossAxisExtent:子widget在交叉軸的最大長度,因為每個子元素的長度仍然是等分的,所以會按照設置的長度計算出能展示的數量然后算出長度的最大值,當maxCrossAxisExtent的值在區間(450/4,450/3]內的話,子元素最終實際長度都為150

GridView.count

GridView.count構造函數內部使用了SliverGridDelegateWithFixedCrossAxisCount,我們通過它可以快速的創建橫軸固定數量子元素的GridView

GridView.count( 
  crossAxisCount: 3,
  childAspectRatio: 1.0,
  children: <Widget>[
    Icon(Icons.ac_unit),
    Icon(Icons.airport_shuttle),
    Icon(Icons.all_inclusive),
    Icon(Icons.beach_access),
    Icon(Icons.cake),
    Icon(Icons.free_breakfast),
  ],
);

GridView.extent

GridView.extent構造函數內部使用了SliverGridDelegateWithMaxCrossAxisExtent,我們通過它可以快速的創建縱軸子元素為固定最大長度的的GridView

GridView.extent(
   maxCrossAxisExtent: 120.0,
   childAspectRatio: 2.0,
   children: <Widget>[
     Icon(Icons.ac_unit),
     Icon(Icons.airport_shuttle),
     Icon(Icons.all_inclusive),
     Icon(Icons.beach_access),
     Icon(Icons.cake),
     Icon(Icons.free_breakfast),
   ],
 );

GridView.builder

上面我們介紹的GridView都需要一個Widget數組作為其子元素,這些方式都會提前將所有子widget都構建好,所以只適用于子Widget數量比較少時,當子widget比較多時,我們可以通過GridView.builder來動態創建子Widget。

GridView.builder 必須指定的參數有兩個:

GridView.builder(
 ...
 @required SliverGridDelegate gridDelegate, 
 @required IndexedWidgetBuilder itemBuilder,
)
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。