states_rebuilder
states_rebuilder copied to clipboard
navigator 2 WillPopScope is not working
With the new navigator 2 WillPopScope is not working. Do we have to override the back button differently with navigator 2?
import 'package:flutter/material.dart';
import 'package:states_rebuilder/states_rebuilder.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routeInformationParser: navigatorRM.routeInformationParser,
routerDelegate: navigatorRM.routerDelegate,
);
}
}
final navigatorRM = RM.injectNavigator(
initialLocation: '/TestPage2',
routes: {
'/TestPage1': (_) => const TestPage1(),
'/TestPage2': (_) => const TestPage2(),
},
);
class TestPage2 extends StatelessWidget {
const TestPage2({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
print('onWillPop page 2');
return false;
},
child: Scaffold(
body: Center(
child: Container(
color: Colors.red,
height: 500,
width: 500,
child: ElevatedButton(
onPressed: () {
navigatorRM.to('/TestPage1');
},
child: const Text('Nav to page 1'),
),
),
),
),
);
}
}
class TestPage1 extends StatelessWidget {
const TestPage1({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
print('onWillPop page 1');
return false;
},
child: Scaffold(
body: Center(
child: Container(
color: Colors.green,
height: 500,
width: 500,
child: ElevatedButton(
onPressed: () {
navigatorRM.to('/TestPage2');
},
child: const Text('Nav to page 2'),
),
),
),
),
);
}
}
@GIfatahTH Would you mind taking a look?
@amoslai5128 @tk2232 I am working on a solution for this issue.
From Flutter docs, WillPopScope.onWillPop
is invoked only if the route is popped using maybePop
method.
maybePop
is implicitly called when the back button of an android device is tapped or when the back arrow of the AppBar
of a Scaffold
is pressed.
See below your example modified so the WillPopScope
is used correctly.
The current nav2 api works well with WillPopScope.
import 'package:flutter/material.dart';
import 'package:states_rebuilder/states_rebuilder.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routeInformationParser: navigatorRM.routeInformationParser,
routerDelegate: navigatorRM.routerDelegate,
);
}
}
final navigatorRM = RM.injectNavigator(
initialLocation: '/TestPage2',
routes: {
'/TestPage1': (_) => const TestPage1(),
'/TestPage2': (_) => const TestPage2(),
},
);
class TestPage2 extends StatelessWidget {
const TestPage2({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
print('onWillPop page 2');
return false;
},
child: Scaffold(
body: Center(
child: Container(
color: Colors.red,
height: 500,
width: 500,
child: ElevatedButton(
onPressed: () {
navigatorRM.to('/TestPage1');
},
child: const Text('Nav to page 1'),
),
),
),
),
);
}
}
class TestPage1 extends StatelessWidget {
const TestPage1({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
print('onWillPop page 1');
return false;
},
child: Scaffold(
appBar: AppBar(),
body: Center(
child: Container(
color: Colors.green,
height: 500,
width: 500,
child: Column(
children: [
Expanded(
child: ElevatedButton(
onPressed: () {
Navigator.of(context).maybePop();
},
child: const Text('Navigate back using maybePop'),
),
),
Expanded(
child: ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
//or
// navigatorRM.back();
},
child: const Text('Navigate back using pop'),
),
),
],
),
),
),
),
);
}
}
@tk2232 @amoslai5128
In the current version, there is the onNavigateBack
parameter of InjectedNavigator
that can be used to globally control the back navigation.
For the next version, I added the OnNavigateBackScope
widget that can be used to locally control all kind of back navigation.
Try this example:
import 'package:flutter/material.dart';
import 'package:states_rebuilder/states_rebuilder.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routeInformationParser: navigatorRM.routeInformationParser,
routerDelegate: navigatorRM.routerDelegate,
);
}
}
final navigatorRM = RM.injectNavigator(
initialLocation: '/TestPage2',
routes: {
'/TestPage1': (_) => const TestPage1(),
'/TestPage2': (_) => const TestPage2(),
},
);
class TestPage2 extends StatelessWidget {
const TestPage2({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Container(
color: Colors.red,
height: 500,
width: 500,
child: ElevatedButton(
onPressed: () {
navigatorRM.to('/TestPage1');
},
child: const Text('Nav to page 1'),
),
),
),
);
}
}
class TestPage1 extends StatelessWidget {
const TestPage1({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return OnNavigateBackScope(
onNavigateBack: () {
RM.navigate.toDialog(
AlertDialog(
content: Text('Are you sure to quit this page'),
actions: [
TextButton(
onPressed: () {
navigatorRM.forceBack();
},
child: Text('YES'),
),
TextButton(
onPressed: () {
navigatorRM.back();
},
child: Text('No'),
),
],
),
postponeToNextFrame: true,
);
return false;
},
child: Scaffold(
appBar: AppBar(),
body: Center(
child: Container(
color: Colors.green,
height: 500,
width: 500,
child: Column(
children: [
Expanded(
child: ElevatedButton(
onPressed: () {
Navigator.of(context).maybePop();
},
child: const Text('Navigate back using maybePop'),
),
),
Expanded(
child: ElevatedButton(
onPressed: () {
Navigator.of(context).pop();
//or
// navigatorRM.back();
},
child: const Text('Navigate back using pop'),
),
),
],
),
),
),
),
);
}
}
I tested OnBackNavigationScope and it works without any problems. Thanks, great job. I would wait for the release version before closing the issue
@GIfatahTH Thanks for the amazing solution, and I really hope this library can get better day by day. Recently I do a project that used VueJS 3, and there is a v-router package feels very user-friendly at some points to me, I think it deserves to be taken a look at. https://router.vuejs.org/guide/
Especially at the "Named Views" section:
Here is an online playground, all the UI widgets were defined in UserSettings.vue
, and route settings in router.js
.
Whenever there is a navigation event, the <router-view>
works like a rebuilder to display the corresponding screen, most importantly the browser back button and history mode work perfectly without any configs needed for the developer.