Flutter 父组件对子组件滚动监听

Flutter Widget树中子Widget可以通过发送通知(Notification)与父(包括祖先)Widget通信。父级组件可以通过NotificationListener组件来监听自己关注的通知。

可滚动组件在滚动时会发送ScrollNotification类型的通知,ScrollBar正是通过监听滚动通知来实现的。通过NotificationListener监听滚动事件和通过ScrollController有两个主要的不同:

  1. NotificationListener可以在可滚动组件到widget树根之间任意位置监听。而ScrollController只能和具体的可滚动组件关联后才可以。
  2. 收到滚动事件后获得的信息不同;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:是否滑到了可滚动组件的边界(此示例中相当于列表顶或底部)。
相关推荐
摘星编程5 分钟前
基于 JiuwenSwarm AgentTeam 构建混沌工程自动化实战
前端·chrome
nashane15 分钟前
HarmonyOS 6学习:Web组件与JavaScript交互的三大高频问题与终极解决方案
前端·学习·harmonyos
顾随23 分钟前
(2)达梦数据库--SQl基础实践
前端·数据库·sql
键盘飞行员24 分钟前
Windsurf + Claude 4.7 前端开发:用 ui-ux-pro-max 根治 “AI 味”、实现全站 UI 统一
前端·ui·ai编程
IT_陈寒25 分钟前
被JavaScript的隐式类型转换坑到怀疑人生,记录这次离谱经历
前端·人工智能·后端
梦无矶25 分钟前
快速设置npm默认源为国内全局镜像源
前端·npm·node.js
aichitang202440 分钟前
HTML 实时预览工具
前端·html
广州智维科技40 分钟前
Kvaser Edge WL400S:工业级边缘计算与 CAN‑FD 数据采集平台解析73-30130-01688-0
前端·edge·边缘计算
吃好睡好便好1 小时前
在Matlab中用sphere( )函数绘制球面图
开发语言·前端·javascript·学习·算法·matlab·信息可视化
黑贝是条狗1 小时前
注册表破解chrome,edge阻止浏览器连接本地websocket
前端·javascript·数据库