使用ScrollNotification和ScrollController

时间:2017-12-30 16:11:09

标签: dart scrollview flutter

有两个选项可以检索CustomScrollView的滚动位置。 documentation声明如下:

  

ScrollNotification和NotificationListener,可用于在不使用ScrollController的情况下观看滚动位置。

所以我们有以下选择:

  1. 带ScrollNotification的NotificationListener
  2. ScrollController
  3. 你在哪种情况下使用NotificationListener和ScrollNotification vs ScrollController?

    谢谢:)

3 个答案:

答案 0 :(得分:5)

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

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();
    }
  },
);

相关答案here

答案 1 :(得分:1)

尽管您可以同时使用ScrollNotification和ScrollController来侦听滚动位置的变化,并且在很多时候并没有什么不同,但是您应该记住一些细节,以便更好地选择最佳的工具来完成这项工作:

ScrollController

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

NotificationListener

  • NotificationListener只是另一个小部件,因此您无需创建有状态的小部件。
  • 当通知向上传播时,它将侦听小部件树中下面所有可滚动小部件的ScrollNotifications。因此,仅侦听一个小部件并没有限制。
  • 您无法从NotificationListener更改滚动位置。它是只读的。
  • 您听的是ScrollNotification,而不是ScrollPosition中的更改,因此您可以轻松识别出刚刚发生的事件之王。

答案 2 :(得分:0)

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

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,
            ),
          ],
        ),
      ),
    );
  }
}