5

Project

Hi, I was trying to build a simple list in flutter with my custom constroller and a listener. Here is the code

class Test2 extends StatefulWidget {
  @override
  _Test2State createState() => _Test2State();
}

class _Test2State extends State<Test2> {
  ScrollController scrollController = ScrollController();

  @override
  void initState() {
    scrollController.addListener((){
      print('controller called');
    });
    super.initState();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: ListView.builder(
          controller: scrollController,
      itemCount: 8,
      itemBuilder: (context, index) {
        return Padding(
          padding: const EdgeInsets.all(8.0),
          child: Container(
            color: Colors.white,
            height: 50,
          ),
        );
      },
    ));
  }
}

Problem

My code works as intented but i'm trying to detect user swipes even when there is nothing to swipe. So far, if the list overflows the screen when user swipe scroll listener is called but, when the list of items is shorter than the screen size, this does not happend. How can i force listener to always listen?

2
  • tried to use NotificationListener instead? Commented Nov 14, 2019 at 17:20
  • Does that detect swipe even when list is too short to be scrolled? Commented Nov 14, 2019 at 17:35

3 Answers 3

9

Maybe this code can help you.

Wrapping the scaffold on a NotificationListener can listen all event,even itemCount is zero

Dont forget provide an AlwaysScrollableScrollPhysics physics object

import 'dart:math' as math;

import 'package:flutter/material.dart';

class TestPage extends StatefulWidget {
  @override
  _TestPageState createState() => _TestPageState();
}

class _TestPageState extends State<TestPage> {
  @override
  Widget build(BuildContext context) {
    final ScrollController scrollController = ScrollController();

    return NotificationListener(
      child: Scaffold(
        body: ListView.builder(
          controller: scrollController,
          physics: const AlwaysScrollableScrollPhysics(),
          itemCount: 0,
          itemBuilder: (context, index) {
            return Container(
              color: Colors.black,
              height: 50,
            );
          },
        ),
      ),
      onNotification: (notificationInfo) {
        if (notificationInfo is ScrollStartNotification) {
          print("scroll");
          print("detail:"+notificationInfo.dragDetails.toString());
          /// your code
        }
        return true;
      },
    );
  }
}
Sign up to request clarification or add additional context in comments.

2 Comments

This does not work right now due to this open issue: github.com/flutter/flutter/issues/44732
If I put a function like scroll to index here, I get multiple errors. Is there a way to identify if user is scrolling right then jump to the next right index and if the user is scrolling left then go the the previous index?
3

You have to pass your custom scroll listener to the function as:

scrollController.addListener(_scrollListener);

Complete:

@override
  void initState() {
    scrollController.addListener(_scrollListener);
    super.initState();
}

and your custom scroll listener method:

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

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

6 Comments

Problem is that scrollListener will not trigger if there isn't an actual scroll. My list in dynamically built and i don't know if the list will overflow screen height
what do you want to do if the list view isn't scrollable?
I want to trigger a set state which will collapse the section
Then why don't you use Wrap( children: <Widget>[]) ) method or column instead? Column( mainAxisSize: MainAxisSize.max, children: <Widget>[], );
Because I don’t know how many list view element will be build. They are dynanic. In the example I hardcoded the number of elements for simplicity
|
0

This is great and all but I wanted to share a way to know if the user has released the scrollView. That's basically when the user has stopped scrolling (even though the scrollView is still scrolling because of the velocity of the users drag.)

Here we would would need to check when the dragDetails is null. This is because the user isn't dragging the screen anymore. It isn't the best solution because there may be edge cases that I haven't seen yet but it works.🙌🏽

NotificationListener<ScrollNotification>(
  onNotification: (ScrollNotification notification) {
    if (notification is ScrollUpdateNotification) {
      if (notification.dragDetails == null) {
        // User has just released the ScrollView
        print('User released the ScrollView');
        // Your code to handle release goes here
      }
    }
    return true;
  },
  child: ListView.builder(
    itemCount: 50,
    itemBuilder: (context, index) => ListTile(
      title: Text('Item $index'),
    ),
  ),
)

(P.S, this is my first answer on StackOverflow. go easy on me🙇🏽)

1 Comment

this only works when the there is velocity in the user's scroll.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.