WillPopScope的回调没有在我预期的时候被触发。我如何WillPopScope在 a 内部使用,Navigator以便路由可以处理它自己的后压行为。
我正在学习使用颤振,我遇到Navigator了创建多个页面的情况(我知道还有其他导航小部件,但我正在寻找只支持程序导航的东西,所以我可以处理所有的用户界面)。
我想看的下一件事Navigator是返回,我发现WillPopScope它包装了一个组件并有一个回调,当按下后退按钮时(如果组件被渲染)被调用。这对我来说似乎很理想,因为我只希望在呈现 Widget 时调用回调。
我尝试WillPopScope在 a 中Navigator使用,目的是仅渲染路由在onWillPop按下后退按钮时调用它的回调 ( ),但放入WillPopScopeaNavigator什么都不做(不调用回调)。
目的是Navigator导航到顶级路线,而这些路线本身可能具有Navigators,因此放入WillPopScope内部意味着每个路线(或子路线)负责它自己的后退导航。
我抬头一看很多问题似乎集中MaterialApp,Scaffold或处理导航等方式; 我正在寻找如何在没有这些东西带来的 UI 的情况下处理这个问题(用例可能是一个测验应用程序,你需要点击下一步按钮继续前进,或类似的东西)。
这是main.dart我希望路由 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}\"");
}
});
})
);
}
}
Run Code Online (Sandbox Code Playgroud)
在路线 1 或路线 2 中按下后退按钮时,应用程序将退出。我希望这只是在路线 1 中的情况,路线 2 应该只记录popping from route 2 disabled(没有导航离开页面或离开应用程序)。
从我的理解,Navigator并且WillPopScope是小工具使用了这样的事情,但如果没有的话我将如何实现自我包含(可能嵌套)的路线。
小智 11
您可以使用以下代码将 onWillPop 转发到另一个导航器:
onWillPop: () async {
return !await otherNavigatorKey.currentState.maybePop();
}
Run Code Online (Sandbox Code Playgroud)
创建导航器时,您将自动创建一个新堆栈。您.push在导航器下方使用的所有内容Navigator.of(context)都将添加到您刚刚创建的新导航器堆栈中。但是,当您按下后退按钮时,它不知道您想要弹出什么(如果是根导航器或新导航器)。
首先,您需要在 Navigator 之外添加一个 WillPopScope 并将 NavigatorKey 添加到您的 Navigator
return WillPopScope(
onWillPop: () => _backPressed(_yourKey),
child: Scaffold(
body: Navigator(
key: _yourKey
onGenerateRoute: _yourMaterialPageRouteLogic,
),
bottomNavigationBar: CustomNavigationBar(navBarOnTapCallback),
),
);
Run Code Online (Sandbox Code Playgroud)
您的密钥可以这样设置
GlobalKey<NavigatorState> _yourKey = GlobalKey<NavigatorState>();
Run Code Online (Sandbox Code Playgroud)
该_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);
Run Code Online (Sandbox Code Playgroud)
接下来,您只需要在导航器内的任何位置添加 WillPopScope。它onWillPop会与你想要的逻辑调用。不要忘记根据您是否要弹出它来返回 true 或 false :)
这是我在小部件中的onWillPop方法 ( _popCamera )的示例,该WillPopScope小部件位于我的导航器小部件树中。在这个例子中,当用户按下相机小部件中的后退按钮时,我添加了一个对话框:
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();
},
),
],
);
}
Run Code Online (Sandbox Code Playgroud)
希望清楚!
| 归档时间: |
|
| 查看次数: |
19592 次 |
| 最近记录: |