前言:
這是我參與8月更文挑戰的第 4 天,活動詳情檢視:8月更文挑戰。為應掘金的八月更文挑戰
,我準備在本月挑選 31
個以前沒有介紹過的元件,進行全面分析和屬性介紹。這些文章將來會作為 Flutter 元件集錄
的重要素材。希望可以堅持下去,你的支援將是我最大的動力~
- 1.【Flutter 元件集錄】NotificationListener| 8月更文挑戰
- 2.【Flutter 元件集錄】Dismissible| 8月更文挑戰
- 3.【Flutter 元件集錄】Switch 是怎樣煉成的| 8月更文挑戰
- 4.【Flutter 元件集錄】Scrollbar| 8月更文挑戰
[本文]
一、Scrollbar 的使用
1. Scrollbar 的效果
在ListView
這種可滑動的元件中,預設情況沒有右側的指示器
,這樣使用者在滑動中不太容易知道滑動進度。使用 Scrollbar
就可以在 右側
出現滑動條。如下分別是在 Android
和 iOS
的效果,可以看出在不同平臺上,Scrollbar
的展示是有所差異的,比如圓角、高度、寬度等。這些我們都能從原始碼中找到根源。
Android 平臺 | iOS 平臺 |
---|---|
從使用的角度來看,Scrollbar
非常簡單,只是在 ListView
外層巢狀一下就行了。然後滑動時就會發現有滾動指示器,這看起來非常神奇。神奇的點在於: ListView
的滑動沒有和 Scrollbar
有任何的直接聯絡, Scrollbar
竟然可以跟隨 ListView
的進行滑動。
class ScrollbarDemo extends StatelessWidget {
const ScrollbarDemo({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scrollbar( //<--- tag1
child: ListView(
children:
List.generate(
60,
(index) => ItemBox(index: index)).toList()),
);
}
}
複製程式碼
這種 可插拔
式的組合,既可以讓元件間幾乎沒有耦合
,又可以讓一方隨另一方進行改變。Scrollbar
雖然在使用上非常簡單,但其背後的這套資料通知
方案是非常值得我們去研究學習的。
2. Scrollbar 的表現屬性
從下面 Scrollbar
的建構函式中可以看出,處了 child
是必傳的入參,還有 8 個 引數,這裡先看一下 isAlwaysShown
、thickness
、radius
三個決定 Scrollbar
顯示的屬性。
Scrollbar(
isAlwaysShown: true, // 是否一直顯示
radius: const Radius.circular(3), // 圓角半徑
thickness: 6,// 線寬
child: ...
);
複製程式碼
如下左側是 安卓平臺預設顯示
效果,可以看出 Scrollbar
只在滑動過程中顯示出來,並且顯隱時伴隨 透明漸變動畫
效果。如下右側上面三個屬性設定後的效果,isAlwaysShown
表示 Scrollbar
是否一直顯示;radius
表示 圓角半徑
;thickness
表示 Scrollbar
滑塊的寬度。
安卓預設顯示 | 本案例顯示 |
---|---|
3. Scrollbar 的尺寸區域
所有可以顯示的元件都會尤其佔據的位置區域,大家可以思考一下 Scrollbar
的尺寸是 包括 ListView
的整體,還是隻是一個細的長條,或只是一個小滑塊。通過 佈局檢視器
可以看出 Scrollbar
的尺寸是包括 ListView
在內的整個一大片。到這裡,我們或多或少可以猜到 Scrollbar
原始碼在佈局上的處理。
猜測 | 答案 |
---|---|
4.可互動性:interactive
如下兩幅圖分別是 interactive:false
和 interactive:true
的效果。它的作用很明顯:如果為 true
時,小滑塊可以接受拖動事件,來控制列表的滑動。在移動端
預設為 false
。
interactive:false | interactive:true |
---|---|
5.回撥通知:notificationPredicate
notificationPredicate
是一個回撥函式,會將 ScrollNotification
物件回撥給使用者,並且返回 bool
值決定是否顯示 Scrollbar
。
@override
Widget build(BuildContext context) {
return Scrollbar(
notificationPredicate: _notificationPredicate,
child: ListView(
children:
List.generate(60, (index) => ItemBox(index: index)).toList()),
);
}
bool _notificationPredicate(ScrollNotification notification) {
print('----$notification---------');
return true;
}
複製程式碼
6.滑動控制器:controller
如果你只為 ListView
指定了 controller
屬性,那麼 Scrollbar
則會報錯。你必須保證兩者有同一個滑動控制器。通過 滑動控制器
我們可以監聽列表的滑動,以及控制滑動。
除此之外,showTrackOnHover
和 hoverThickness
兩個屬性顧名思義是懸浮時的效果,這一般只在 非移動端
裝置上有效果,另外,目前 ListView
在桌面端中預設自帶 Scrollbar
。
到這裡 Scrollbar
所有的屬性用法就已經介紹完畢。下面簡單地看一下 Scrollbar
的原始碼實現,不止於是知道怎麼用,還能對它的內部機制有一點了解,原始碼中的一些邏輯處理,這或許在某些場景中能對你產生幫助,多瞭解一些總沒什麼壞處。知其然,知其所以然,你把握的才夠通透
。
二、Scrollbar 原始碼簡看
1. Scrollbar 類定義
從下面可以看出 Scrollbar
是一個 StatefulWidget
,通過 _ScrollbarState
狀態類構建元件。
下面是 _ScrollbarState
的全部程式碼,通過如果是 iOS
平臺,則構建 CupertinoScrollbar
,否則構建 _MaterialScrollbar
。
這是 _ScrollbarState
的全部原始碼,不過我從這裡看不出 Scrollbar 是 StatefulWidget 的必要性
。不知你有什麼見解。
2. 滑動事件的監聽和滑塊的移動
CupertinoScrollbar
和 _MaterialScrollbar
都是繼承自 RawScrollbar
,也就是說它們的底層邏輯是一樣的,只不過根據平臺進行一定的適配。
在 RawScrollbarState
構建元件程式碼中可以看到,使用了 NotificationListener
監聽 ScrollNotification
通知,執行 _handleScrollNotification
方法。如果不瞭解 NotificationListener
元件,可以看一下第一篇
在 _handleScrollNotification
中有一些比較核心的邏輯,其中 notificationPredicate
回撥會先觸發,如果該函式返回 false
,也就意味著_handleScrollNotification
返回 false
,下面的邏輯不會被執行。這也是為什麼返回 false
時,滑塊不顯示的原因。下面會執行透明漸變動畫,以及根據 notification
資訊更新 scrollbarPainter
畫板,這是滑塊可以跟隨列表滑動最核心的處理。
3.滑塊的繪製
在 RawScrollbarState#build
方法的最後,是通過前景畫板 foregroundPainter
進行繪製,child
為出傳入的 ListView
,這也是為什麼 Scrollbar
的尺寸區域是整個一片的原因。
繪製的畫板是 ScrollbarPainter
,在狀態初始化時被建立。
ScrollbarPainter
繼承自 ChangeNotifier
,並實現 CustomPainter
,也就是說它既是可見聽物件,又是畫板,也就說明它自己可以通知進行畫板重繪,使用這裡 ScrollbarPainter
是以成員變數的方式宣告的,在需要更新時,自己執行更新。這也很值得我們學習借鑑,原始碼是最好的老師。至於具體的繪製邏輯,就不說了,有興趣的自己看看。
Scrollbar 元件
的使用方式到這裡就介紹完畢,那本文到這裡就結束了,謝謝觀看,明天見~