Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get the scroll direction of a NestedScrollView

Tags:

flutter

dart

I'm trying to get the scroll direction (Up/Down) of a NestedScrollView so one of my widgets can react accordingly.

I've already used the NotificationListener widget and tried to print the axisDirection that it returns but it only returns "down" when I scroll in both directions. apparently that's the way it supposed to behave but still, it doesn't look like there's any way in Flutter to know how to get the scroll direction. Is there any way to get the scroll direction whether be it as an AxisDirection or a bool ?.

@override
  Widget build(BuildContext context) {

    return Container(
      color: Colors.black,
      child: SafeArea(
        child: Scaffold(
          backgroundColor: Color.fromARGB(255, 22, 22, 22),
          body: NotificationListener<ScrollStartNotification>(
            onNotification: (ScrollNotification scrollInfo) {


              print("scrollInfo up ===== ${scrollInfo.metrics.axisDirection}");


            },
            child: NotificationListener<ScrollStartNotification>(
              onNotification: (ScrollNotification scrollInfo) {
                if (scrollInfo.metrics.axisDirection == AxisDirection.down) {
                  print(
                      "scrollViewColtroller down == ${scrollViewColtroller.position.axisDirection}");
                }
              },
              child: NestedScrollView(
                controller: scrollViewColtroller,
                headerSliverBuilder:
                    (BuildContext context, bool boxIsScrolled) {
                  return <Widget>[
                    SliverAppBar(
                      floating: true,
                      snap: true,
                      pinned: false,
                      elevation: 10,
                    )
                  ];
                },
                body: Container(
                  padding: EdgeInsets.all(0.0),
                  child: Center(
                    child: Column(
                      children: <Widget>[
                        SizedBox(
                          height: 1,
                        ),
                        _feedPosts(context)
                      ],
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }

This is what it prints.

scrollViewColtroller up ===== AxisDirection.down
scrollInfo up == AxisDirection.down
scrollViewColtroller up ===== AxisDirection.down
scrollInfo up == AxisDirection.down
like image 707
john haris Avatar asked Aug 23 '19 05:08

john haris


2 Answers

You can get the Direction with the help of - scrollViewColtroller.position

First add - import 'package:flutter/rendering.dart';

Code:

    @override
  Widget build(BuildContext context) {
    return Scaffold(
      //  backgroundColor: Color.fromARGB(255, 22, 22, 22),
      body: NotificationListener<ScrollUpdateNotification>(
        onNotification: (ScrollNotification scrollInfo) {
          if (scrollViewColtroller.position.userScrollDirection ==
              ScrollDirection.reverse) {
            print('User is going down');
            setState(() {
              message = 'going down';
            });
          } else {
            if (scrollViewColtroller.position.userScrollDirection ==
                ScrollDirection.forward) {
              print('User is going up');
              setState(() {
                message = 'going up';
              });
            }
          }
        },
        child: NestedScrollView(
          controller: scrollViewColtroller,
          headerSliverBuilder: (BuildContext context, bool boxIsScrolled) {
            return <Widget>[
              SliverAppBar(
                floating: true,
                snap: true,
                pinned: false,
                elevation: 10,
              )
            ];
          },
          body: Container(
            padding: EdgeInsets.all(0.0),
            child: Column(
              children: <Widget>[
                Container(
                  height: 150.0,
                  color: Colors.green,
                  child: Align(
                    alignment: Alignment.bottomCenter,
                    child: Text(
                      message,
                      style: TextStyle(color: Colors.white, fontSize: 25.0),
                    ),
                  ),
                ),
                Expanded(
                    child: ListView(
                  children: List.generate(100, (i) {
                    return Text(i.toString());
                  }).toList(),
                ))
              ],
            ),
          ),
        ),
      ),
    );
  }

Output: enter image description here

like image 59
anmol.majhail Avatar answered Nov 18 '22 20:11

anmol.majhail


AxisDirection isn't used to detect scrolling direction, it is used to return the Scrollable structure, in your case the NestedScrollView has scrollDirection = Axis.Vertical by default, which makes its beginning at top and its AxisDirection = AxisDirection.down. So when you tried to scroll up and down you received the same result because list structure doesn't change by scrolling events.

To achieve what you want you can compare the current position to the default one (0.0), if the ScrollNotification.metrics.pixels greater than previous position, then the list is scrolling up (or left in case of horizontal ones), or down if it is less.

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  final appTitle = 'Scroll Direction Detection';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: appTitle,
      home: MyHomePage(title: appTitle),
    );
  }
}

class MyHomePage extends StatefulWidget {
  final String title;

  MyHomePage({Key key, this.title}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>{

  double position = 0.0 ;

  double sensitivityFactor = 20.0 ;

  @override
  Widget build(BuildContext context) {

    return Container(
      child: SafeArea(
        child: Scaffold(
          appBar: AppBar(
            title: Text(widget.title),
          ),
          body: NotificationListener<ScrollNotification>(
            onNotification: (ScrollNotification scrollInfo) {
              if(scrollInfo.metrics.pixels - position >= sensitivityFactor){
                print('Axis Scroll Direction : Up');
                position = scrollInfo.metrics.pixels ;
              }
              if(position - scrollInfo.metrics.pixels  >= sensitivityFactor){
                print('Axis Scroll Direction : Down');
                position = scrollInfo.metrics.pixels ;
              }

            },
            child: ListView.builder(
              itemCount: 100,
              itemBuilder: (context, index) {
                return ListTile(
                  title: Text('$index'),
                );
              },
            ),
          ),
        ),
      ),
    );
  }
}
like image 37
Mazin Ibrahim Avatar answered Nov 18 '22 22:11

Mazin Ibrahim