Reputation: 2322
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
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
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
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
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
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
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
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
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
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
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