Search code examples
flutterscrollflutter-pageview

Flutter - PageView - Only scroll when you swipe on top of a specific component instead of any location of the page


Totally new to flutter, less than 10h on it.

I have a PageView handing 3 pages, it scrolls horizontally through them perfectly.

But I would like to change the "allowed swipe" area. I don't want to let the user change the pages scrolling from any position of the page, but instead, for example, just let him scroll the pages if he swipes on the AppBar component for example.

I saw the PageView has the applyTo method, I'm just lost about how to give to it the ID(keys) or the appBar to see if this will work.

Is there a way of achieving this "only scroll if the user swipes on the component X"?


Edit 1

Solution suggested by Alberto Miola works like a charm, here is my code (I had to implement from PreferredSizeWidget since is required to modify the AppBar).

class GestureDetectorForAppBar extends StatelessWidget implements PreferredSizeWidget {
  final double height;
  final AppBar appbar;
  final GestureDragUpdateCallback onPanUpdate;

  GestureDetectorForAppBar({
    Key key,
    this.appbar,
    this.onPanUpdate,
    @required this.height,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(child: this.appbar, onPanUpdate: this.onPanUpdate,);
  }

  @override
  Size get preferredSize => Size.fromHeight(height);
}

Solution

  • First of all, you need to "block" the swipe gesture on the PageView itself using NeverScrollableScrollPhysics:

    PageView(
      physics: const NeverScrollableScrollPhysics(),
      children: [...],
      controller: ...
    );
    

    Note the usage of a const constructor. In this way you won't be able to move among pages with your finger. In Flutter you have widgets and not components.


    Give a look at the GestureDetector widget which can be used to listen on swipes and change the currently visible content of your PageView. It can be used to detect swipes:

    GestureDetector(
      onPanUpdate: (data) {
        if (data.delta.dx > 0) {
          // right swipe
        } 
    
        if (data.delta.dx < 0) {
          // right swipe
        }
      }
    );
    

    In order, I suggest you to first read about NeverScrollableScrollPhysics() in the official documentation. It's used to "block" scrolling behaviors. Then, use GestureDetector() to wrap the widget you want to be used as a "scroll director" (the one that actually scrolls the pages).

    Inside onPanUpdate you'll deal with the animateToPage method of the PageController to change the currently visible page.