Govaadiyo
Govaadiyo

Reputation: 6082

ScrollController how can I detect Scroll start, stop and scrolling?

I'm using a ScrollController for a SingleChildScrollView widget where I want to detect scroll start, scroll end/stop and still scrolling.

How can I detect this?

I'm using Listener

    scrollController = ScrollController()
          ..addListener(() {
            scrollOffset = _scrollController.offset;
          });

Also try with _scrollController.position.activity.velocity but didn't help me.

Also there are

    _scrollController.position.didEndScroll();
    _scrollController.position.didStartScroll();

But how can I use it?

Upvotes: 46

Views: 74668

Answers (8)

Azmi Rutkay BIYIK
Azmi Rutkay BIYIK

Reputation: 116

I created an extension to make things easier:

import 'package:flutter/widgets.dart';

extension ScrollControllerExtension on ScrollController {
  void addScrollEndListener(VoidCallback onScrollEnd) {
    addListener(() {
      if (position.pixels == position.maxScrollExtent) {
        onScrollEnd();
      }
    });
  }
}

and the usage is:

final _scrollController = ScrollController();

@override
void initState() {
  super.initState();

  _scrollController.addScrollEndListener(
    () {
      fetchMore();
    },
  );
}

@override
void dispose() {
  _scrollController.dispose();

  super.dispose();
}

Upvotes: 1

aqibGenk
aqibGenk

Reputation: 141

update 2023 : to check scroll stop after scrolling

if(notification.direction == ScrollDirection.idle)

Upvotes: 0

goodonion
goodonion

Reputation: 1779

There's a package for this use case. scroll_edge_listener

You can detect either the start or the end of the scroll with a few configurations such as offset and debounce. Just wrap your scroll view with the ScrollEdgeListener and attach a listener.

ScrollEdgeListener(
  edge: ScrollEdge.end,
  edgeOffset: 400,
  continuous: false,
  debounce: const Duration(milliseconds: 500),
  dispatch: true,
  listener: () {
    debugPrint('listener called');
  },
  child: ListView(
    children: const [
      Placeholder(),
      Placeholder(),
      Placeholder(),
      Placeholder(),
    ],
  ),
),

Upvotes: 0

K_Chandio
K_Chandio

Reputation: 777

You can use _scrollController.position.pixels for getting scroll position and addlistener to be notified about changes

if(_scrollController.position.pixels == _scrollController.position.maxScrollExtent){
//for scroll end
}

if(_scrollController.position.pixels == _scrollController.position.minScrollExtent){
//for scroll at top
}

Upvotes: 2

The Vinh Luong
The Vinh Luong

Reputation: 1183

No need for NotificationListener, we can use solely scroll controller for this.

First, register a post-frame callback by using WidgetsBinding.instance.addPostFrameCallback to make sure that the scroll controller by that time has already associated with a scroll view. We will setup listener in that callback.

For listening to scrolling update we can use scrollController.addListener.

For listening to start and stop scrolling we can use bgScrollCtrl.position.isScrollingNotifier.addListener. You can check the code below:

WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
      scrollCtrl.addListener(() { 
        print('scrolling');
      });
      scrollCtrl.position.isScrollingNotifier.addListener(() { 
        if(!scrollCtrl.position.isScrollingNotifier.value) {
          print('scroll is stopped');
        } else {
          print('scroll is started');
        }
      });
    });

Upvotes: 67

Abdullah Khan
Abdullah Khan

Reputation: 1481

NotificationListner not work for me because i animate scrollview. When i touch it ScrollEndNotification is called.

So to detect scrollview reach bottom or top. I added Listner to scrollcontroller.

  _scrollController.addListener(_scrollListener);

  _scrollListener() {
    if (_scrollController.offset >= _scrollController.position.maxScrollExtent &&
        !_scrollController.position.outOfRange) {
      setState(() {
        debugPrint("reach the top");
      });
    }
    if (_scrollController.offset <= _scrollController.position.minScrollExtent &&
        !_scrollController.position.outOfRange) {
      setState(() {
        debugPrint("reach the top");
      });
    }
  }

Upvotes: 3

iPatel
iPatel

Reputation: 47049

From this link https://medium.com/@diegoveloper/flutter-lets-know-the-scrollcontroller-and-scrollnotification-652b2685a4ac

Just Wrap your SingleChildScrollView to NotificationListener and update your code like ..

NotificationListener<ScrollNotification>(
                onNotification: (scrollNotification) {
                  if (scrollNotification is ScrollStartNotification) {
                    _onStartScroll(scrollNotification.metrics);
                  } else if (scrollNotification is ScrollUpdateNotification) {
                    _onUpdateScroll(scrollNotification.metrics);
                  } else if (scrollNotification is ScrollEndNotification) {
                    _onEndScroll(scrollNotification.metrics);
                  }
                },
                child: SingleChildScrollView(
                /// YOUR OWN CODE HERE
               )
)

And just declare method like

_onStartScroll(ScrollMetrics metrics) {
    print("Scroll Start");
  }

  _onUpdateScroll(ScrollMetrics metrics) {
    print("Scroll Update");
  }

  _onEndScroll(ScrollMetrics metrics) {
    print("Scroll End");
  }

You will be notify by particular method.

Upvotes: 59

Murat Aslan
Murat Aslan

Reputation: 1580

_scrollController.position.pixels

if(_scrollController.position.pixels == _scrollController.position.maxScrollExtent){
//scroll end
}

to use these, you should add a listener to your scrollview

Upvotes: 5

Related Questions