James Gilchrist
James Gilchrist

Reputation: 2322

Flutter: Disable Swipe to Navigate Back in iOS and Android

I'm new to flutter development, and find it a bit frustrating in iOS when you have a navigation drawer and when you swipe to open it, it'll perform a Navigation.of(context).pop(). I would like to disable this "swipe to pop" behavior in iOS. I have been perusing the documentation, but without much luck.

I do see something referred to as a WillPopScope which seems to do the trick (github issue for it here), but I'm not 100% sure if this is the "correct" way to do it (it seems too complicated... it should be easier... like a setting on the root app).

Upvotes: 46

Views: 66384

Answers (10)

Emerson Paduan
Emerson Paduan

Reputation: 1

Update for 2025:

Widget build(BuildContext context) {
    return PopScope(
      canPop: false, // this prevent the pop
      child: Scaffold(
        appBar: AppBar(
          title: Text("My App"),
        ),
       ),
    );
}

Upvotes: 0

WaterFlow
WaterFlow

Reputation: 111

You can try this in your Widget build:

@override
  Widget build(BuildContext context) {
    return WillPopScope(
      //forbidden swipe from userGestureInProgress
      onWillPop: () async => !(Navigator.of(context).userGestureInProgress),
      child: <your child>,
    );
  }

Upvotes: 11

Arkolium
Arkolium

Reputation: 131

Update for new Flutter version : WillPopScope is now became PopScope with a easier canPop properties

PopScope(
  canPop : false,
  child : --child here--
)

This code should do the trick

Upvotes: 13

Jan Pavlovsk&#253;
Jan Pavlovsk&#253;

Reputation: 574

I have one additional point here. I was just solving this problem, but I also needed my user to be able to go back by pressing the "native" back button on the AppBar (did not want to reimplement AppBar just because of this), and I found this niche little flag: userGestureInProgress on the Navigator object, so what I use (and presume is the preferred way) is:

onWillPop: () async {
    return !Navigator.of(context).userGestureInProgress;
},

Upvotes: 41

Jitesh Mohite
Jitesh Mohite

Reputation: 34270

Whenever the back button or Swipe gesture(iOS) is pressed, you will get a callback at onWillPop, which returns a Future. If the Future returns true, the screen is popped(i.e navigate to the previous screen), If it is false, then it doesn't navigate back.

Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () {
        return Future.value(false);
      },
      child: Scaffold(
        appBar: AppBar(title: Text("Second Screen"),),
        body: Center(

And if you want to pop screen on a condition basis then declare

bool shouldPop = true; // change this using setState() inside build on the requirement. 

  onWillPop: () {
        return Future.value(shouldPop? true: false);
      },

Upvotes: 4

R&#233;mi Rousselet
R&#233;mi Rousselet

Reputation: 277667

WillPopScope is the correct way to do this.

(it seems too complicated... it should be easier... like a setting on the root app).

It is not complicated. It's a one liner :

WillPopScope(
  onWillPop: () async => false,
  child: <children here>
)

A configuration file would make things more complicated as it's harder to read and maintain.

And remember that in flutter everything is a widget not just half of them. Authentification, configurations, everything.

Upvotes: 76

Merouane T.
Merouane T.

Reputation: 876

I had a similar problem where I wanted to block the swipe to return back in navigation (default pop function). This code helped fix the problem.

@override
Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async => false,
      child: Scaffold(
        body: Center(
          child: Text('Example'),
        ),
      ),
    );
  }

This code now blocks the back navigation for iOS & Android (default back button) and that's exactly what I was looking for. Hope this helps.

Upvotes: 6

MisterJimson
MisterJimson

Reputation: 549

MaterialPageRoute has a parameter called fullscreenDialog which is set to false by default. When true your page animates a bit differently and swipe to go back on iOS will be disabled.

Example usage:

 Navigator.of(context).push(
        MaterialPageRoute(builder: (_) => HomePage(), fullscreenDialog: true));

See some discussion here: https://github.com/flutter/flutter/issues/14203

Upvotes: 34

mquemazz
mquemazz

Reputation: 823

I am not quite sure what you want to achieve, but most of the time when people want to get rid of the back functionality, because they don't wanna enable the user to control the auth mechanism. For example after the users log in, you don't want them to navigate to the Login page by just press on the back button(or swipe back in iOS). A potential solution is, using pushNamedAndRemoveUntil.

Future<T> pushNamedAndRemoveUntil<T extends Object>(BuildContext context, String newRouteName, RoutePredicate predicate)

Push the route with the given name onto the navigator that most tightly encloses the given context, and then remove all the previous routes until the predicate returns true.

Example code: pushNamedAndRemoveUntil(context, '/home', ModalRoute.withName('/home'));

Note: use this method to some certain extent, because you might mess up your navigation history.

Upvotes: 3

James Gilchrist
James Gilchrist

Reputation: 2322

Alright, so as @Darky said WillPopScope is a perfectly acceptable answer, however, if you want to disable it across the board you can actually do the following.

Open your project in xcode, find AppDelegate.swift and add the following:

let controller: FlutterViewController
    = window?.rootViewController as! FlutterViewController;
controller.navigationController?
    .interactivePopGestureRecognizer?.isEnabled = false;

Upvotes: 3

Related Questions