歷史上的今天
魏文帝曹丕(187年-226年6月29日),字子桓,沛國譙縣(今屬安徽亳州)人。三國時期曹魏開國皇帝,曹操和卞夫人的嫡長子,之後繼承父親的魏王封號與丞相的大權,最終東漢皇帝漢獻帝禪讓於其,曹丕登基後改國號為魏,史稱曹魏,226年駕崩,諡文皇帝。
正文
默認情況下,Flutter 的滾動組件(比如 ListView)沒有顯示滾動條,使用 Scrollbar 顯示滾動條:
<code>Scrollbar( child: ListView.builder( reverse: false, itemBuilder: (BuildContext context, int index) { return Card( child: Container( height: 45, alignment: Alignment.center, child: Text('$index'), ), ); }, itemCount: 30, itemExtent: 50, ), ) /<code>
在滑動的過程中,右側顯示滾動條,然而 Scrollbar 無法實現自定義滾動條的樣式,比如實現如下滾動條樣式,
這時需要自定義一個滾動條組件。
實現自定義滾動條組件首先需要監聽滾動組件 滾動的位置,使用 NotificationListener 監聽滾動的位置:
<code>bool _handleScrollNotification(ScrollNotification notification) { final ScrollMetrics metrics = notification.metrics; print('滾動組件最大滾動距離:${metrics.maxScrollExtent}'); print('當前滾動位置:${metrics.pixels}'); return true; } @override Widget build(BuildContext context) { return NotificationListener( onNotification: _handleScrollNotification, child: ListView.builder( reverse: false, itemBuilder: (BuildContext context, int index) { return Card( child: Container( height: 45, alignment: Alignment.center, child: Text('$index'), ), ); }, itemCount: 30, itemExtent: 50, ), ); } /<code>
通過 ScrollNotification 獲取當前滾動組件最大滾動距離和當前滾動位置,其中 metrics.maxScrollExtent 表示當前滾動組件最大滾動距離,metrics.pixels 表示當前滾動位置。
通過這兩個值計算滾動條在當前屏幕的位置,通過 Stack 組件 將 ListView 和 自定義的滾動條進行疊加顯示:
<code>NotificationListener( onNotification: _handleScrollNotification, child: Stack( alignment: Alignment.topRight, children: [ ListView.builder( reverse: false, itemBuilder: (BuildContext context, int index) { return Card( child: Container( height: 45, alignment: Alignment.center, child: Text('$index'), ), ); }, itemCount: 30, itemExtent: 50, ), //滾動條 Container( height: 100, width: 20, color: Colors.red, ) ], ), ) /<code>
將此滾動條和 NotificationListener 監聽到的滾動事件聯動,通過 Container 的 alignment 屬性控制滾動條的位置:
<code>Container( alignment: Alignment(1, _alignmentY), padding: EdgeInsets.only(right: 5), child: Container( height: 100, width: 20, color: Colors.red, ), ) /<code>
_alignmentY 就是計算出的偏移位置,計算方法如下:
<code>_alignmentY = -1 + (metrics.pixels / metrics.maxScrollExtent) * 2; /<code>
這裡要注意 alignment 的座標系:
最終效果:
然後只需修改滾動條的樣式即可:
<code>class _ScrollBar extends StatelessWidget { @override Widget build(BuildContext context) { return Container( width: 18, height: 60, decoration: BoxDecoration( shape: BoxShape.rectangle, borderRadius: BorderRadius.all(Radius.circular(20)), color: Colors.blue), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.arrow_drop_up, size: 18, ), Icon( Icons.arrow_drop_down, size: 18, ), ], ), ); } } /<code>
最後將代碼封裝,就可以給所有的滾動組件添加自定義的滾動條,而不僅僅是 ListView。
本文使用 mdnice 排版