Flutter(七)——多子元素組件:GridView,CustomScrollView,Flex,Wrap

前言

上一篇介紹了多元素組件:ListView,Scaffold,AppBar,Row,Column,這一節將接着上一篇博文,介紹GridView,CustomScrollView,Flex,以及Wrap多元素組件(下圖爲CustomScrollView實現效果)
CustomScrollView

GridView

首先,就是GridView,它和ListView相似,只不過表現形式爲網格形式,可以把它看成Android的LayoutManager。如果GridView組件掌握的很好,那麼App界面也是會非常好看,給人賞心悅目。不過需要注意的是,GridView中的gridDelegate屬性,其類型是SliverGridDelegate,是一個抽象類,通過該類可以控制GridView的排列顯示方式,我們先來看看官方文檔的使用方式:

body: GridView.count(
        primary: false,
        padding: const EdgeInsets.all(20.0),
        crossAxisSpacing: 10.0,
        crossAxisCount: 2,
        children: <Widget>[
          const Text("11111111111111111111"),
          const Text("22222222222222222222"),
          const Text("33333333333333333333"),
          const Text("44444444444444444444"),
          const Text("55555555555555555555"),
          const Text("66666666666666666666"),
        ],
      ),

這裏我們沒有看到代碼中使用SliverGridDelegate,那麼它在哪裏呢?其實,在GridView.count中的構造函數裏已經傳入了默認的gridDelegate,通過開發工具我們進入它的源碼:

gridDelegate = SliverGridDelegateWithFixedCrossAxisCount(
         crossAxisCount: crossAxisCount,
         mainAxisSpacing: mainAxisSpacing,
         crossAxisSpacing: crossAxisSpacing,
         childAspectRatio: childAspectRatio,
       ),

源碼裏已經使用了SliverGridDelegateWithFixedCrossAxisCount。它有四個屬性,我們先來看看他們的定義:

屬性 取值
crossAxisCount 橫向軸子元素的數量
mainAxisSpacing 橫向軸之間的間距
crossAxisSpacing 子元素之間的間距
childAspectRatio 子元素的寬高比,比如2.0就表示寬度是高度的2倍

gridDelegate還支持SliverGridDelegateWithMaxCrossAxisExtent,同時GridView也和ListView一樣支持GridView.builder來創建,使用代碼與ListView差不多,這裏就不在贅述了,上面代碼實現效果如下:
GridView

CustomScrollView

在實際應用裏,佈局情況並不是非此即彼,一般一個界面不會只有一個滾動列表組件,很可能還有別的組件,這個時候CustomScrollView就有用處了,它的使用代碼如下:

return CustomScrollView(
      slivers: <Widget>[
        const SliverAppBar(
          pinned: true,//標題欄是否固定
          expandedHeight: 250.0,//合併的高度,默認是狀態欄的高度加AppBar的高度
          flexibleSpace: FlexibleSpaceBar(
            title: Text("我的標題"),
          ),
        ),
        SliverGrid(
            delegate: SliverChildBuilderDelegate((BuildContext context,int index){
              return Container(
                alignment: Alignment.center,
                color: Colors.teal[100*(index%9)],
                child: Text("第$index個"),
              );
            },childCount: 20),
            gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
                maxCrossAxisExtent: 200.0,//單個子Widget的水平最大寬度
                mainAxisSpacing: 10.0,//水平單個子Widget之間間距
                crossAxisSpacing: 10.0,//垂直單個子Widget之間間距
                childAspectRatio: 4.0,//寬高比
            )
        ),
        SliverFixedExtentList(
          itemExtent: 50.0,
          delegate: SliverChildBuilderDelegate((BuildContext context,int index){
            return Container(
              alignment: Alignment.center,
              color: Colors.lightBlue[100*(index%9)],
              child: Text("第$index個"),
            );
          }),
        ),
      ],
    );

這段代碼看起來非常複雜其實很好理解,在Scaffold中,Appbar等價於SliverAppBar,剛講解的GridView等價於SliverGrid,而ListView等價於SliverFixedExtentList,所以這是一個包含了二個滑動組件的一個佈局容器,其他的代碼中有註釋,這裏就不贅述了。(顯示效果如博文首圖)

特別注意:轉換後的組件都是以“Sliver”開頭的,其本身是不具備滾動特性的,但是放在CustomScrollView中之後,則可以實現滾動的功能。

Flex

Flex英文意思是屈伸,活動,在Flutter裏面也就是彈性佈局,該佈局借鑑了前端裏的Flex佈局方式。用法也十分簡單,我們可以在Flex中傳入一些參數,其具體屬性如下表:

屬性 取值
direction Axis.vertical表示垂直方向,Axis.horizontal表示水平方向
flex 彈性係數,大於0會按比例來分割,等於0不會擴展佔用的空間

可以把它理解爲android:layout_weight屬性,使用代碼如下:

return Scaffold(
      appBar: AppBar(title: Text("Flex佈局玩法"),),
      body: Column(
        children: <Widget>[
          Container(
            height: 400.0,
            child: Flex(
              direction: Axis.vertical,
              children: <Widget>[
                Expanded(
                  flex: 1,
                  child: Container(
                    color: Colors.red,
                  ),
                ),
                Expanded(
                  flex: 2,
                  child: Container(
                    color: Colors.yellow,
                  ),
                ),
              ],
            ),
          ),
          Container(
            height: 120.0,
            child: new Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                Expanded(
                  flex: 2,
                  child: Container(
                   color: Colors.blueAccent,
                  ),
                ),
                Expanded(
                  flex: 1,
                  child: Container(
                    color: Colors.red,
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );

上面的例子中,我們實現了Flex佈局。這種佈局還有一種方式,它通過在Row組件裏設置兩邊對齊也可以實現,代碼顯示效果如下:
Flex

Wrap

Wrap英文字面是包裹的意思,在前端開發中,我們通常把具有相同的佈局整合在一個大的佈局組件之內,比如說前面一節使用Row去包裹一些組件,因爲它是多子元素組件,但是Row有時候會出問題,比如實際子組件超過屏幕,在這種情況下,我們就需要使用Wrap去代替Row組件,使用代碼如下:

return Scaffold(
      appBar: AppBar(title: Text("Wrap組件玩法"),),
      body: Wrap(
        spacing: 4.0,
        runSpacing: 4.0,
        children: <Widget>[
          Container(
            color: Colors.yellow,
            child: Text("Python編程指南",style: new TextStyle(color: Colors.lightBlue),),
          ),
          Container(
            color: Colors.yellow,
            child: Text("Android編程指南",style: new TextStyle(color: Colors.lightBlue),)
          ),
          Container(
              color: Colors.yellow,
              child: Text("Flutter",style: new TextStyle(color: Colors.lightBlue),)
          ),
          Container(
              color: Colors.yellow,
              child: Text("VUE",style: new TextStyle(color: Colors.lightBlue),)
          ),
          Container(
              color: Colors.yellow,
              child: Text("Scaffold",style: new TextStyle(color: Colors.lightBlue),)
          ),
          Container(
              color: Colors.yellow,
              child: Text("Container",style: new TextStyle(color: Colors.lightBlue),)
          ),
          Container(
              color: Colors.yellow,
              child: Text("Colors",style: new TextStyle(color: Colors.lightBlue),)
          ),
          Container(
              color: Colors.yellow,
              child: Text("Colors.yellow",style: new TextStyle(color: Colors.lightBlue),)
          ),
        ],
      ),
    );

其實就是自適應控件佈局容器,當一行放不下的時候會自動換行顯示,這在Java開發中並沒有配套的控件,需要自定義View,而Flutter開發中,直接提供了該組件,實現效果如下:
Wrap
多子元素組件到這裏就全部講解完成,下一篇博文將介紹Flutter狀態管理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章