老孟导读:【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】: