老孟导读:【Flutter实战】系列文章地址:http://laomengit.com/guide/introduction/mobile_system.html

默认情况下,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个控件用法):http://laomengit.com

欢迎加入Flutter交流群(微信:laomengit)、关注公众号【老孟Flutter】: