【Flutter實戰】自定義滾動條

老孟Flutter發表於2020-06-28

老孟導讀:【Flutter實戰】系列文章地址:laomengit.com/guide/intro…

預設情況下,Flutter 的滾動元件(比如 ListView)沒有顯示滾動條,使用 Scrollbar 顯示滾動條:

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,
  ),
)複製程式碼

在滑動的過程中,右側顯示滾動條,然而 Scrollbar 無法實現自定義滾動條的樣式,比如實現如下滾動條樣式,

這時需要自定義一個滾動條元件。

實現自定義滾動條元件首先需要監聽滾動元件 滾動的位置,使用 NotificationListener 監聽滾動的位置:

bool _handleScrollNotification(ScrollNotification notification) {
    final ScrollMetrics metrics = notification.metrics;
    print('滾動元件最大滾動距離:${metrics.maxScrollExtent}');
    print('當前滾動位置:${metrics.pixels}');
    return true;
  }

  @override
  Widget build(BuildContext context) {
    return NotificationListener<ScrollNotification>(
      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,
      ),
    );
  }複製程式碼

通過 ScrollNotification 獲取當前滾動元件最大滾動距離和當前滾動位置,其中 metrics.maxScrollExtent 表示當前滾動元件最大滾動距離,metrics.pixels 表示當前滾動位置。

通過這兩個值計算滾動條在當前螢幕的位置,通過 Stack 元件 將 ListView 和 自定義的滾動條進行疊加顯示:

NotificationListener<ScrollNotification>(
  onNotification: _handleScrollNotification,
  child: Stack(
    alignment: Alignment.topRight,
    children: <Widget>[
      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,
      )
    ],
  ),
)複製程式碼

將此滾動條和 NotificationListener 監聽到的滾動事件聯動,通過 Container 的 alignment 屬性控制滾動條的位置:

Container(
  alignment: Alignment(1, _alignmentY),
  padding: EdgeInsets.only(right: 5),
  child: Container(
    height: 100,
    width: 20,
    color: Colors.red,
  ),
)複製程式碼

_alignmentY 就是計算出的偏移位置,計算方法如下:

_alignmentY = -1 + (metrics.pixels / metrics.maxScrollExtent) * 2;複製程式碼

這裡要注意 alignment 的座標系:

最終效果:

然後只需修改滾動條的樣式即可:

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: <Widget>[
          Icon(
            Icons.arrow_drop_up,
            size: 18,
          ),
          Icon(
            Icons.arrow_drop_down,
            size: 18,
          ),
        ],
      ),
    );
  }
}複製程式碼

最後將程式碼封裝,就可以給所有的滾動元件新增自定義的滾動條,而不僅僅是 ListView。

交流

老孟Flutter部落格地址(330個控制元件用法):laomengit.com

歡迎加入Flutter交流群(微信:laomengit)、關注公眾號【老孟Flutter】:

相關文章