title: How can I make the scrollController.listener listen to changes?
body: <p>I have to files: one which contains my app's code and another which contains a widget. The constructor of that widget has as parameter a child of type <code>SingleChildScrollView</code>. The widget takes child's <code>ScrollController</code> and attach to it a listener. The problem is that the listener... doesn't listen. It doesn't detect any state. How can I make it listen to changes?</p>
  <p>Here is my code:</p>
  <p><em>app.dart - the file with my app's code</em></p>
  <pre class="lang-dart prettyprint-override"><code>import 'package:flutter/material.dart';
  import 'MyWidget.dart';
  
  class MyTestPage2 extends StatelessWidget {
    const MyTestPage2({Key? key}) : super(key: key);
  
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: Center(
          child: MyWidget(
              child: SingleChildScrollView(
            scrollDirection: Axis.horizontal,
            physics:
                BouncingScrollPhysics(parent: AlwaysScrollableScrollPhysics()),
            controller: ScrollController(),
            child: Text(
              '1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30',
              style: TextStyle(fontSize: 30),
              maxLines: 1,
            ),
          )),
        ),
      );
    }
  }
  </code></pre>
  <p><em>MyWidget.dart - the file with the problematic widget</em></p>
  <pre class="lang-dart prettyprint-override"><code>import 'package:flutter/material.dart';
  
  class MyWidget extends StatefulWidget {
    final SingleChildScrollView child;
    final ScrollController scrollController;
  
    MyWidget({
      Key? key,
      required this.child,
    })  : assert(child.controller != null,
              'You need to provide a ScrollController to the child'),
          scrollController = child.controller!,
          super(key: key);
  
    @override
    _MyWidget createState() =&gt; _MyWidget();
  }
  
  class _MyWidget extends State&lt;MyWidget&gt; {
    @override
    void initState() {
      widget.scrollController.addListener(_onScroll);
      super.initState();
    }
  
    void _onScroll() {
      final offset = widget.scrollController.offset;
      final minOffset = widget.scrollController.position.minScrollExtent;
      final maxOffset = widget.scrollController.position.maxScrollExtent;
      final isOutOfRange = widget.scrollController.position
          .outOfRange;
  
      final hasReachedTheEnd = offset &gt;= maxOffset &amp;&amp; !isOutOfRange;
      final hasReachedTheStart = offset &lt;= minOffset &amp;&amp; !isOutOfRange;
      final isScrolling = maxOffset &gt; offset &amp;&amp; minOffset &lt; offset;
  
      // This code doesn't print anything.
      if (isScrolling) {
        print('isScrolling');
      } else if (hasReachedTheStart) {
        print('hasReachedTheStart');
      } else if (hasReachedTheEnd) {
        print('hasReachedTheEnd');
      } else {
        print('IDK');
      }
    }
  
    @override
    void dispose() {
      widget.scrollController.removeListener(_onScroll);
      widget.scrollController.dispose();
      super.dispose();  
  }
  
    @override
    Widget build(BuildContext context) {
      return widget.child;
    }
  }
  </code></pre>