前言
當組件內容超過當前顯示視口(ViewPort)時,如果沒有特殊處理,Flutter則會提示Overflow錯誤。為此,Flutter提供了多種可滾動組件(Scrollable Widget)用於顯示列表和長布局。
可滾動組件都直接或間接包含一個Scrollable組件,它們包括一些共同的屬性,接口如下:
Scrollable({
...
// 滾動方向
this.axisDirection = AxisDirection.down,
// 此屬性接受一個ScrollController對象。ScrollController的主要作用是控制滾動位置和監聽滾動事件。
// 默認情況下,Widget樹中會有一個默認的PrimaryScrollController,如果子樹中的可滾動組件沒有顯式的指定controller,並且primary屬性值為true時(默認就為true),
// 可滾動組件會使用這個默認的PrimaryScrollController。這種機制帶來的好處是父組件可以控制子樹中可滾動組件的滾動行為,
// 例如,Scaffold正是使用這種機制在iOS中實現了點擊導航欄回到頂部的功能。
this.controller,
// 此屬性接受一個ScrollPhysics類型的對象,它決定可滾動組件如何響應用戶操作,比如用戶滑動完抬起手指后,繼續執行動畫;或者滑動到邊界時,如何顯示。
// 默認情況下,Flutter會根據具體平台分別使用不同的ScrollPhysics對象,應用不同的顯示效果,如當滑動到邊界時,繼續拖動的話,在iOS上會出現彈性效果,而在Android上會出現微光效果。
// 如果想在所有平台下使用同一種效果,可以顯式指定一個固定的ScrollPhysics,Flutter SDK中包含了兩個ScrollPhysics的子類。
this.physics,
@required this.viewportBuilder, //后面介紹
})
Scrollbar
Scrollbar是一個Material風格的滾動指示器(滾動條),如果要給可滾動組件添加滾動條,只需將Scrollbar作為可滾動組件的任意一個父級組件即可。例如:
Scrollbar(
child: SingleChildScrollView(
...
),
);
Scrollbar和CupertinoScrollbar都是通過監聽滾動通知來確定滾動條位置的。
ViewPort視口
在很多布局系統中都有ViewPort的概念,在Flutter中,術語ViewPort(視口),如無特別說明,則是指一個Widget的實際顯示區域。例如,一個ListView的顯示區域高度是800像素,雖然其列表項總高度可能遠遠超過800像素,但是其ViewPort仍然是800像素。
基於Sliver的延遲構建
通常可滾動組件的子組件可能會非常多、占用的總高度也會非常大;如果要一次性將子組件全部構建出將會非常昂貴!為此,Flutter中提出一個Sliver(中文為“薄片”的意思)概念,如果一個可滾動組件支持Sliver模型,那么該滾動可以將子組件分成好多個“薄片”(Sliver),只有當Sliver出現在視口中時才會去構建它,這種模型也稱為“基於Sliver的延遲構建模型”。可滾動組件中有很多都支持基於Sliver的延遲構建模型,如ListView、GridView,但是也有不支持該模型的,如SingleChildScrollView。
主軸和縱軸
在可滾動組件的坐標描述中,通常將滾動方向稱為主軸,非滾動方向稱為縱軸。由於可滾動組件的默認方向一般都是沿垂直方向,所以默認情況下主軸就是指垂直方向,水平方向同理。