Ștefan Neagu
Ștefan Neagu

Reputation: 29

How can I make the scrollController.listener listen to changes?

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 SingleChildScrollView. The widget takes child's ScrollController 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?

Here is my code:

app.dart - the file with my app's 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,
          ),
        )),
      ),
    );
  }
}

MyWidget.dart - the file with the problematic widget

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

class _MyWidget extends State<MyWidget> {
  @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 >= maxOffset && !isOutOfRange;
    final hasReachedTheStart = offset <= minOffset && !isOutOfRange;
    final isScrolling = maxOffset > offset && minOffset < 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;
  }
}

Upvotes: 1

Views: 4510

Answers (1)

Emad Adly
Emad Adly

Reputation: 131

As per testing on an emulator, the listener seems working and the log messages are being written on scrolling events. I suggest trying to fully restart the App or reinstall it, also you may revise the widgets tree if you are using the widget as a child for other widgets.

Console output - App Screenshot

Upvotes: 1

Related Questions