Flutter NotificationListener与ScrollNotification和ScrollController

Ren*_*fer 5 scrollview dart flutter

有两个选项可检索CustomScrollView的滚动位置。该文档指出以下内容:

ScrollNotification和NotificationListener,可用于查看滚动位置,而无需使用ScrollController。

因此,我们有以下选择:

  1. 带ScrollNotification的NotificationListener
  2. ScrollController

在哪种情况下,您将NotificationListener与ScrollNotification vs ScrollController一起使用?

谢谢 :)

Mic*_*dla 11

如果NestedScrollView与嵌套滚动条一起使用,则在内滚动条上使用scrollController会断开链接,其NestedScrollView含义NestedScrollView将不再控制完整的滚动体验。在这种情况下,要获取有关内部滚动条的滚动位置的信息,可以使用NotificationListenerwith ScrollNotification

NotificationListener<ScrollNotification>(
  child: ListView.builder(
    itemCount: 10
    itemBuilder: (BuildContext context, int index) {
      return Text('Item $index');
    },
  ),
  onNotification: (ScrollNotification scrollInfo) {
    if (scrollInfo.metrics.pixels ==
        scrollInfo.metrics.maxScrollExtent) {
      onLoadMore();
    }
  },
);
Run Code Online (Sandbox Code Playgroud)

相关答案在这里

  • 在您的情况下,一旦用户停止滚动时发出通知,最好使用 ScrollEndNotification 而不是 ScrollNotification。 (4认同)

小智 7

虽然你可以同时使用 ScrollNotification 和 ScrollController 来监听滚动位置的变化,而且很多时候不会有什么不同,但你应该记住一些细节,以便更好地选择最适合工作的工具:

滚动控制器

  • 要使用 ScrollController,您应该使用 Stateful 小部件,以便可以正确处置它。
  • 即使您可以使用同一个 ScrollController 来控制多个可滚动小部件,但某些操作(例如读取滚动偏移量)需要将控制器与单个可滚动小部件一起使用。
  • 如果你想改变滚动位置,你需要一个 ScrollController (jumpTo / animateTo)。
  • 当您收听 ScrollController 时,您正在收听ScrollPosition 的变化,这与ScrollNotification不完全相同。使用 ScrollNotifications,您可以区分与滚动操作相关的几种类型的事件,例如滚动开始、滚动结束、方向更改等。

通知监听器

  • NotificationListener 只是另一个小部件,所以你不需要创建一个有状态的小部件。
  • 当通知向上传播时,它会监听来自小部件树中下方所有可滚动小部件的 ScrollNotifications。所以只听一个小部件不是约束。
  • 您不能从 NotificationListener 更改滚动位置。它是只读的。
  • 您收听 ScrollNotification,而不是 ScrollPosition 中的更改,因此您可以轻松识别刚刚发生的事件之王。


王良海*_*王良海 5

我的演示使用NotificationListener 和ScrollController。向左拖动一个垃圾后,蓝色部分会自动移动

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    List<Widget> list = [];
    for (int i = 0; i < 100; i++) list.add(buildContainer());
    return Scaffold(
        body: ListView(children: list));
  }

  Widget buildContainer() {
    ScrollController _scrollController = ScrollController();

    return NotificationListener<ScrollNotification>(
      onNotification: (scrollState) {
        if (scrollState is ScrollEndNotification && scrollState.metrics.pixels != 160) {
          Future.delayed(const Duration(milliseconds: 100), () {}).then((s) {
            _scrollController.animateTo(160,
                duration: Duration(milliseconds: 500), curve: Curves.ease);
          });
        }
        return false;
      },
      child: Container(
        height: 160,
        margin: EdgeInsets.only(bottom: 1),
        child: ListView(
          shrinkWrap: true,
          scrollDirection: Axis.horizontal,
          controller: _scrollController,
          children: <Widget>[
            Container(
              width: 360,
              height: 20,
              color: Colors.red,
            ),
            Container(
              width: 160,
              height: 20,
              color: Colors.blue,
            ),
          ],
        ),
      ),
    );
  }
}
Run Code Online (Sandbox Code Playgroud)