Flutter Widget树中子Widget可以通过发送通知(Notification)与父(包括祖先)Widget通信。父级组件可以通过NotificationListener
组件来监听自己关注的通知。
可滚动组件在滚动时会发送ScrollNotification
类型的通知,ScrollBar
正是通过监听滚动通知来实现的。通过NotificationListener
监听滚动事件和通过ScrollController
有两个主要的不同:
- NotificationListener可以在可滚动组件到widget树根之间任意位置监听。而
ScrollController
只能和具体的可滚动组件关联后才可以。 - 收到滚动事件后获得的信息不同;
NotificationListener
在收到滚动事件时,通知中会携带当前滚动位置和ViewPort的一些信息,而ScrollController
只能获取当前滚动位置。
less
import 'package:flutter/material.dart';
class ScrollNotificationTestRoute extends StatefulWidget {
@override
_ScrollNotificationTestRouteState createState() =>
_ScrollNotificationTestRouteState();
}
class _ScrollNotificationTestRouteState
extends State<ScrollNotificationTestRoute> {
String _progress = "0%"; //保存进度百分比
@override
Widget build(BuildContext context) {
return Scrollbar(
//进度条
// 监听滚动通知
child: NotificationListener<ScrollNotification>(
onNotification: (ScrollNotification notification) {
double progress = notification.metrics.pixels /
notification.metrics.maxScrollExtent;
//重新构建
setState(() {
_progress = "${(progress * 100).toInt()}%";
});
print("BottomEdge: ${notification.metrics.extentAfter == 0}");
return false;
//return true; //放开此行注释后,进度条将失效
},
child: Stack(
alignment: Alignment.center,
children: <Widget>[
ListView.builder(
itemCount: 100,
itemExtent: 50.0,
itemBuilder: (context, index) => ListTile(title: Text("$index")),
),
CircleAvatar(
//显示进度百分比
radius: 30.0,
child: Text(_progress),
backgroundColor: Colors.black54,
)
],
),
),
);
}
}
在接收到滚动事件时,参数类型为ScrollNotification
,它包括一个metrics
属性,它的类型是ScrollMetrics
,该属性包含当前ViewPort及滚动位置等信息:
pixels
:当前滚动位置。maxScrollExtent
:最大可滚动长度。extentBefore
:滑出ViewPort顶部的长度;此示例中相当于顶部滑出屏幕上方的列表长度。extentInside
:ViewPort内部长度;此示例中屏幕显示的列表部分的长度。extentAfter
:列表中未滑入ViewPort部分的长度;此示例中列表底部未显示到屏幕范围部分的长度。atEdge
:是否滑到了可滚动组件的边界(此示例中相当于列表顶或底部)。