WillPopScope
的回调在我期望的时候没有被触发。如何在WillPopScope
中使用Navigator
,以便路由可以处理自己的后按行为。
我正在学习使用颤动,并且偶然发现Navigator
用于创建多个页面(我知道还有其他导航小部件,但是我只支持程序化导航,因此我可以处理所有UI )。
我想用Navigator
查看的下一件事是回退,我发现WillPopScope
包装了一个组件,并具有一个回调,当按下后退按钮时,该回调将被调用(如果该组件呈现)。这对我来说很理想,因为我只希望在呈现Widget的情况下才调用回调。
我试图在WillPopScope
中使用Navigator
,目的是仅在按下后退按钮时才使渲染的路由调用其回调(onWillPop
),但将{{ WillPopScope
中的1}}无效(未调用回调)。
目的是让Navigator
导航到顶级路线,而这些路线本身可能具有Navigator
,因此将Navigator
放入其中意味着每个路线(或子路线)负责它是自己的后退导航。
我查询的许多问题似乎都集中在WillPopScope
,MaterialApp
或其他处理导航的方式上;我正在寻找如何在没有这些东西带来的UI的情况下处理此问题(一个用例可能是一个测验应用程序,在该应用程序中,您需要单击下一步按钮才能前进,或者类似的操作)。
这里是最小的Scaffold
文件,我希望路线2可以处理它自己的后退导航(为简单起见,在此示例中我没有放置嵌套路线)。
main.dart
在路线1或2中按下后退按钮时,应用程序退出。我希望只有在路由1中才是这种情况,路由2应该只记录import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Navigation',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override
Widget build(BuildContext parentContext) {
return Container(
color: Theme.of(context).colorScheme.primary,
child: Navigator(
initialRoute: "1",
onGenerateRoute: (settings) {
return PageRouteBuilder(pageBuilder: (BuildContext context,
Animation animation, Animation secondaryAnimation) {
switch (settings.name) {
case "1":
return Container(
color: Colors.red,
child: GestureDetector(onTap: () {
debugPrint("going from 1 to 2");
Navigator.of(context).pushNamed("2");
}));
case "2":
return WillPopScope(
child: Container(color: Colors.green),
onWillPop: ()async {
debugPrint("popping from route 2 disabled");
return false;
},
);
default:
throw Exception("unrecognised route \"${settings.name}\"");
}
});
})
);
}
}
(没有离开页面的导航或离开应用程序)。
据我了解,popping from route 2 disabled
和Navigator
是用于此类事情的小部件,但是如果没有,那么我将如何实现自包含(可能嵌套)的路由。
答案 0 :(得分:5)
您可以使用以下代码将onWillPop转发到另一个导航器:
mapview.annotations
答案 1 :(得分:3)
创建导航器时,将自动创建新的堆栈。使用.push
在导航器下Navigator.of(context)
的所有内容都会添加到您刚刚创建的新导航器堆栈中。但是,当您按下后退按钮时,它不知道要弹出的内容(如果是根导航器或新导航器)。
首先,您需要在导航器外部添加WillPopScope并将NavigatorKey添加到导航器
return WillPopScope(
onWillPop: () => _backPressed(_yourKey),
child: Scaffold(
body: Navigator(
key: _yourKey
onGenerateRoute: _yourMaterialPageRouteLogic,
),
bottomNavigationBar: CustomNavigationBar(navBarOnTapCallback),
),
);
您的钥匙可以像这样
GlobalKey<NavigatorState> _yourKey = GlobalKey<NavigatorState>();
_backPressed
方法将收到您在设备上执行的所有backPressed。根据定义,它返回true
,我们并不总是希望弹出。
我们已经在导航器中添加了一个密钥,现在它将用于了解新导航器是否在堆栈中有任何东西可以弹出(例如,如果它是'canPop')。
Future<bool> _backPressed(GlobalKey<NavigatorState> _yourKey) async {
//Checks if current Navigator still has screens on the stack.
if (_yourKey.currentState.canPop()) {
// 'maybePop' method handles the decision of 'pop' to another WillPopScope if they exist.
//If no other WillPopScope exists, it returns true
_yourKey.currentState.maybePop();
return Future<bool>.value(false);
}
//if nothing remains in the stack, it simply pops
return Future<bool>.value(true);
接下来,您只需要在导航器内的任何位置添加WillPopScope。其onWillPop
将用您需要的逻辑进行调用。不要忘记根据是否要弹出返回真或假:)
这里是onWillPop
小部件中我的WillPopScope
方法( _popCamera )的示例,该小部件位于我的导航器小部件树中。在此示例中,当用户按下Camera Widget中的“后退”按钮时,我添加了一个对话框:
static Future<bool> _popCamera(BuildContext context) {
debugPrint("_popCamera");
showDialog(
context: context,
builder: (_) => ExitCameraDialog(),
barrierDismissible: true);
return Future.value(false);
}
class ExitCameraDialog extends StatelessWidget {
const ExitCameraDialog({
Key key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return AlertDialog(
title: Text('Leaving camera forever'),
content:
Text('Are you S-U-R-E, S-I-R?'),
actions: <Widget>[
FlatButton(
child: Text('no'),
onPressed: Navigator.of(context).pop,
),
FlatButton(
//yes button
child: Text('yes'),
onPressed: () {
Navigator.of(context).pop();
_yourKey.currentState.pop();
},
),
],
);
}
希望很清楚!