Flutter Widget树中子Widget能够经过发送告诉(Notification)与父(包含祖先)Widget通信。父级组件能够经过NotificationListener组件来监听自己关注的告诉。

可翻滚组件在翻滚时会发送ScrollNotification类型的告诉,ScrollBar正是经过监听翻滚告诉来完成的。经过NotificationListener监听翻滚事情和经过ScrollController有两个主要的不同:

  1. NotificationListener能够在可翻滚组件到widget树根之间任意方位监听。而ScrollController只能和具体的可翻滚组件相关后才能够。
  2. 收到翻滚事情后获得的信息不同;NotificationListener在收到翻滚事情时,告诉中会带着当时翻滚方位和ViewPort的一些信息,而ScrollController只能获取当时翻滚方位。
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:是否滑到了可翻滚组件的鸿沟(此示例中相当于列表顶或底部)。