【Flutter实战】自定义滚动条

老孟导读:【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,int index) {
          return Card(
            child: Container(
              height: 45,);
        },);
  }

通过 ScrollNotification 获取当前滚动组件最大滚动距离和当前滚动位置,其中 metrics.maxScrollExtent 表示当前滚动组件最大滚动距离,metrics.pixels 表示当前滚动位置。

通过这两个值计算滚动条在当前屏幕的位置,通过 Stack 组件 将 ListView 和 自定义的滚动条进行叠加显示

NotificationListener<ScrollNotification>(
  onNotification: _handleScrollNotification,child: Stack(
    alignment: Alignment.topRight,children: <Widget>[
      ListView.builder(
        reverse: false,//滚动条
      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,)

_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,],);
  }
}

最后将代码封装,就可以给所有的滚动组件添加自定义的滚动条,而不仅仅是 ListView。

交流

老孟Flutter博客地址(330个控件用法):http://laomengit.com

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

相关文章

在Android上运行OpenGL ES程序需要用到GLSurfaceView控件,GLSurfaceView继承自SurfaceView并实现了GLT...
经过半年的准备OpenGL ES for Android系列文章终于要和大家见面了,在这里定一个小目标-先吸引1000个粉...
经过半年的准备OpenGL ES for Android系列文章终于要和大家见面了,在这里定一个小目标-先吸引1000个粉...
注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7....
Flutter 学习路线图 如果你真的觉得很难,坚持不了了,那就放弃,既然放弃了就不要抱怨没有得到。 选择...
在Flutter默认创建的项目中可以使用系统Material图标,在 文件中使用图标设置如下: 系统图标如下: 如...