Flutter進階:深入探究 ListView 和 ScrollPhysics

Flutter 中的 ListView 可以對比 Android 中的 ListView 或者 RecycleView(當然也有不同之處) ,是可滾動項的線性列表。 我們可以用它來製作可滾動專案列表或重複專案列表。
探究各型別的 ListView
構建 ListView 有以下幾種方式:
- ListView
- ListView.builder
- ListView.separated
- ListView.custom
ListView
這是 ListView 類的預設建構函式。 ListView 內有任意個數的子元素都可使其滾動。
程式碼的格式為:
ListView( children: <Widget>[ ItemOne(), ItemTwo(), ItemThree(), ], ), 複製程式碼
通常這裡應該放少量的子元素,因為 ListView 也會將當前不可見的元素構建起來,因此大量的子元素可能使 App 效能降低。
ListView.builder()
builder() 建構函式可以用來構造重複的子項列表,這裡我們就可以類比 Android 中的 ListView 。 這個建構函式有兩個主要引數:列表中專案數的 itemCount 和構造每個列表子項的 itemBuilder。

程式碼的格式為:
ListView.builder( itemCount: itemCount, itemBuilder: (context, position) { return listItem(); }, ), 複製程式碼
列表項是 懶載入 的,這表明 Flutter 只構造了特定數量的列表項,當用戶滾動時,早期的列表項被銷燬。
技巧:由於元素是懶載入的,只加載了所需數量的元素,我們並不需要將 itemCount 作為必需引數,列表可以是 無限長 的。
ListView.builder( itemBuilder: (context, position) { return Card( child: Padding( padding: const EdgeInsets.all(16.0), child: Text(position.toString(), style: TextStyle(fontSize: 22.0),), ), ); }, ), 複製程式碼

ListView.separated()
在 separate() 的建構函式中,我們同樣生成一個列表,但這裡我們可以指定每個項之間的分隔符。

實質上,這裡, 我們構造了兩個交織列表 :一個作為主列表,一個作為分隔符列表。
要注意的是,這裡不能應用前面建構函式中所說的無限長度,因為此建構函式會強制執行 itemCount 。
程式碼的格式為:
ListView.separated( itemBuilder: (context, position) { return ListItem(); }, separatorBuilder: (context, position) { return SeparatorItem(); }, itemCount: itemCount, ), 複製程式碼
這種型別的列表允許您動態定義分隔符,為不同型別的子項分配不同型別的分隔符,在需要時新增或刪除分隔符等。
該實現還可以在列表中方便地插入其他型別的子元素(例如廣告),而不需要對列表項中的主列表進行任何修改。

**注意:**通常分隔符列表長度比專案列表小 1,因為在最後一個元素之後不存在分隔符。
ListView.custom()
正如其名,custom() 建構函式允許我們自定義構建 ListViews。 需要的主要引數是 SliverChildDelegate ,用於構建子項。 SliverChildDelegates 的型別是:
- verChildListDelegate
- SliverChildBuilderDelegate
SliverChildListDelegate 接受一個子項的直接列表,而 SliverChildBuiderDelegate 接受 IndexedWidgetBuilder(我們使用的建構函式)。
您可以使用或子類化這些來構建自己的委託。
ListView 預設建構函式的行為類似於帶有 SliverChildListDelegate 的 ListView.custom 。
我們已經介紹完了 ListViews 的各種型別,讓我們來看看 ScrollPhysics 。
探究 ScrollPhysics
為了控制列表滾動的發生方式,我們在 ListView 的建構函式中通常需要設定 physics 引數。 各種型別的 physics 引數有:
NeverScrollablePhysics
NeverScrollablePhysics 表現為不可滾動的列表。 使用此選項可以完全禁用 ListView 的滾動。
BouncingScrollPhysics
BouncingScrollPhysics 在列表結束時 退回 列表。 iOS 中有類似的效果。

ClampingScrollPhysics
這是 Android 上使用的預設滾動方式。 列表在結尾處停止並給出一定的效果。

FixedExtentScrollPhysics
該方法與其他方法略有不同,因為它僅適用於 FixedExtendScrollControllers 和使用它們的列表。 舉個例子,我們用 ListWheelScrollView 來製作類似輪子的列表。
FixedExtentScrollPhysics 僅滾動到子項而不存在任何偏移。

樣例程式碼非常簡單:
FixedExtentScrollController fixedExtentScrollController = new FixedExtentScrollController(); ListWheelScrollView( controller: fixedExtentScrollController, physics: FixedExtentScrollPhysics(), children: monthsOfTheYear.map((month) { return Card( child: Row( children: <Widget>[ Expanded( child: Padding( padding: const EdgeInsets.all(8.0), child: Text( month, style: TextStyle(fontSize: 18.0), ), )), ], )); }).toList(), itemExtent: 60.0, ), 複製程式碼
你應當知道的其他事情
如何在列表中保留被破壞的元素?
Flutter 提供了一個 KeepAlive() 小元件,它可以使子元素保持活躍狀態,否則會被破壞。 在列表中,預設情況下,元素包裝在 AutomaticKeepAlive 中。

為什麼我的 ListView 在列表和外部小部件之間有空格?
ListView 在它與外部視窗元件之間有預設填充,將填充設定為 EdgeInsets.all(0.0) 就可以刪除它。