Flutter入門並開發天氣預報APP(5)——SingleChildScrollView、ListView和GridView


下面我們來介紹下Flutter中的滑動控件SingleChildScrollView、列表ListView和表格GridView

1. SingleChildScrollView

SingleChildScrollView類似於Android中的ScrollView,我使用的較淺,在我目前看來,他和ScrollView的唯一區別就是它還可以橫向滾動。

我們先來看下他的定義:

SingleChildScrollView({
  this.scrollDirection = Axis.vertical, //滾動方向,默認是垂直方向
  this.reverse = false, 
  this.padding, 
  bool primary, 
  this.physics, 
  this.controller,
  this.child,
})
  • scrollDirection:設定滾動的方向,可以設定Axis.vertical或者Axis.horizon
  • reverse:是否按照閱讀方向的反方向滑動,emmm這個可能有點覺得莫名其妙,但是如阿拉伯語言地區,他們閱讀和我國古時候一樣是從右向左的,所以如果reversetrue,且滾動方向是水平滾動的話,如果系統時阿拉伯語等從右向左閱讀的語言時,方向是從右向左的;
  • padding:留白的大小,和Padding的用法一樣,通過EdgeInsets來設定,具體可以看前幾章將Flutter基礎Widget;
  • primary:指是否使用widget樹中默認的PrimaryScrollController;當滑動方向爲垂直方向(scrollDirection值爲Axis.vertical)並且沒有指定controller時,primary默認爲true
  • physics:用於控制滾動方式,這個等會重點講解;
  • controller:用於滾動監聽及控制;
  • child:子Widget。

1.2 physics

這個參數是用於控制滾動方式,有幾種參數:

  • NeverScrollablePhysics:呈現不可滾動狀態;
  • BouncingScrollPhysics:當列表滑動結束時,會回彈列表,類似於iOS的列表滑動效果;

BouncingScrollPhysics

  • ClampingScrollPhysics:滑動結束時會顯示水波紋陰影,類似於Android的列表滑動效果;

ClampingScrollPhysics

  • FixedExtentScrollPhysics:可以自己製作滑動效果,但是我也不會,所以在此不做解釋?。

2. ListView

ListView可以沿一個方向上線性排布所有子組件(不僅侷限於豎直方向)。

讓我們來看下他的定義:

ListView({
  ...  
  //可滾動widget公共參數
  Axis scrollDirection = Axis.vertical,
  bool reverse = false,
  ScrollController controller,
  bool primary,
  ScrollPhysics physics,
  EdgeInsetsGeometry padding,

  //ListView各個構造函數的共同參數  
  double itemExtent,
  bool shrinkWrap = false,
  bool addAutomaticKeepAlives = true,
  bool addRepaintBoundaries = true,
  double cacheExtent,

  //子widget列表
  List<Widget> children = const <Widget>[],
})

公共屬性我們就不講了,上面SingleChildScrollView已經講過了,我們現在只講他特有的:

  • itemExtent:用於控制ListView的長度,如果不爲null,則強制所有子Widget合起來的長度小於設定的值:如果ListView是橫向的,則所有子Widget橫向長度的和小於它;如果ListView是縱向的,則所有子Widget縱向長度的和小於它;
  • shrinkWrap:該屬性表示是否根據子組件的總長度來設置ListView的長度,默認值爲false 。默認情況下,ListView的會在滾動方向儘可能多的佔用空間。當ListView在一個無邊界(滾動方向上)的容器中時,shrinkWrap必須爲true
  • addAutomaticKeepAlives:該屬性表示是否將列表項(子組件)包裹在AutomaticKeepAlive組件中;典型地,在一個懶加載列表中,如果將列表項包裹在AutomaticKeepAlive中,在該列表項滑出視口時它也不會被GC(垃圾回收),它會使用KeepAliveNotification來保存其狀態。如果列表項自己維護其KeepAlive狀態,那麼此參數必須置爲false
  • addRepaintBoundaries:該屬性表示是否將列表項(子組件)包裹在RepaintBoundary組件中。當可滾動組件滾動時,將列表項包裹在RepaintBoundary中可以避免列表項重繪,但是當列表項重繪的開銷非常小(如一個顏色塊,或者一個較短的文本)時,不添加RepaintBoundary反而會更高效。和addAutomaticKeepAlive一樣,如果列表項自己維護其KeepAlive狀態,那麼此參數必須置爲false
  • cacheExtent:設定緩存大小。

默認情況下一個一個設定children很麻煩,所以爲了方便,Flutter還提供了一個builder構造方法:

2.1 ListView.builder

ListView.builder({
  // ListView公共參數已省略  
  ...
  @required IndexedWidgetBuilder itemBuilder,
  int itemCount,
  ...
})
  • itemCount:是需要加載子Widget的長度;
  • itemBuilder:列表項的構造器,當列表滾動到具體的index位置時,會調用該構建器構建列表項。

看例子:

ListView.builder(
  itemCount: _provinces.length,
  itemBuilder: (context, index) {
    return GestureDetector(
      child: ListTile(
        title: Text("$index"),
      ),
      onTap: () {}));
      },
    );
  },
)

ListViewBuilder

2.2 ListView.separated

用於添加分割線。相較於ListView.builder多了一個separatorBuilder參數,該參數是一個分割組件生成器。

下面我們看一個例子:奇數行添加一條藍色下劃線,偶數行添加一條綠色下劃線。

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;
        },
    );
  }
}

-w160

3. GridView

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>[],
})

大部分參數和ListView都相同,我們只關注gridDelegate這個參數:
gridDelegate作用是控制GridView子組件如何排列,Flutter中提供了兩個類SliverGridDelegateWithFixedCrossAxisCountSliverGridDelegateWithMaxCrossAxisExtent,我們可以直接使用,下面我們分別來介紹一下它們。

3.1 SliverGridDelegateWithFixedCrossAxisCount

該子類實現了一個橫軸爲固定數量子元素的layout算法,其構造函數爲:

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

3.2 SliverGridDelegateWithMaxCrossAxisExtent

該子類實現了一個橫軸子元素爲固定最大長度的layout算法,其構造函數爲:

SliverGridDelegateWithMaxCrossAxisExtent({
  double maxCrossAxisExtent,
  double mainAxisSpacing = 0.0,
  double crossAxisSpacing = 0.0,
  double childAspectRatio = 1.0,
})

maxCrossAxisExtent爲子元素在橫軸上的最大長度,之所以是“最大”長度,是因爲橫軸方向每個子元素的長度仍然是等分的。其它參數和SliverGridDelegateWithFixedCrossAxisCount相同。

3.3 GridView.builder

ListView一樣,當子Widget數量較多時,也提供了builder方法:

GridView.builder(
 ...
 @required SliverGridDelegate gridDelegate, 
 @required IndexedWidgetBuilder itemBuilder,
)

這個就不在這舉例了,gridDelegate和前面一樣的,itemBuilderListView的一樣的。

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