android - 用于嵌套导航的 Flutter WillPopScope
问题描述
我有带有嵌套导航器的 Flutter App,我想WillPopScope
在我的嵌套屏幕中覆盖“onBackPressed”。
假设我有MainScreen
,PrimaryScreen
和SecondaryScreen
。
PrimaryScreen
是嵌套导航器,它有几个屏幕,如PrimaryOneScreen
,PrimaryTwoScreen
和PrimaryThreeScreen
.
SecondaryScreen
也是一个嵌套的导航器,就像它一样PrimaryScreen
,它有 3 个屏幕。
这里是我想要实现的插图
MainScreen
-> PrimaryScreen
( PrimaryOneScreen
-> PrimaryTwoScreen
-> PrimaryThreeScreen
)
当我的位置上时PrimaryTwoScreen
,我想回到PrimaryOneScreen
使用WillPopScope
Widget 覆盖“onBackPressed”。但是onWillPop
当我按下后退按钮时从未调用过,我的屏幕直接返回到MainScreen
.
这是我的代码
主屏幕.dart
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MainApp(),
onGenerateRoute: (settings){
WidgetBuilder builder;
switch(settings.name){
case 'primary' :
builder = (BuildContext _) => PrimaryScreen();
break;
case 'secondary' :
builder = (BuildContext _) => SecondaryScreen();
break;
case 'main' :
builder = (BuildContext _) => MainApp();
break;
default :
throw Exception('Invalid route: ${settings.name}');
}
return MaterialPageRoute(
builder: builder,
settings: settings
);
},
);
}
}
class MainApp extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
FlatButton(
onPressed: (){
Navigator.pushNamed(context, 'primary');
},
child: Text('To Page Primary'),
),
FlatButton(
onPressed: (){
Navigator.pushNamed(context, 'secondary');
},
child: Text('To Page Secondary'),
)
],
),
);
}
}
PrimaryScreen.dart
class PrimaryScreen extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Navigator(
initialRoute: 'primary/pageone',
onGenerateRoute: (RouteSettings settings){
WidgetBuilder builder;
switch(settings.name){
case 'primary/pageone' :
builder = (BuildContext _) => PrimaryOneScreen();
break;
case 'primary/pagetwo' :
builder = (BuildContext _) => PrimaryTwoScreen();
break;
case 'primary/pagethree' :
builder = (BuildContext _) => PrimaryThreeScreen();
break;
default :
throw Exception('Invalid route: ${settings.name}');
}
return MaterialPageRoute(
builder: builder,
settings: settings
);
},
);
}
}
PrimaryOneScreen.dart
class PrimaryOneScreen extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Primary Page'),
),
body: Center(
child: Column(
children: <Widget>[
FlatButton(
onPressed: (){
Navigator.pushNamed(context, 'primary/pagetwo');
},
child: Text('To Page Two'),
),
FlatButton(
onPressed: (){
Navigator.pushNamed(context, 'primary/pagethree');
},
child: Text('To Page Three'),
),
],
),
),
);
}
}
PrimaryTwoScreen.dart
class PrimaryTwoScreen extends StatelessWidget{
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: ()async{
print('willPopScope');
Navigator.of(context, rootNavigator: false).pop();
return true;
},
child: Scaffold(
appBar: AppBar(
title: Text('Secondary Page'),
),
body: Center(
child: Column(
children: <Widget>[
FlatButton(
onPressed: (){
Navigator.pushNamed(context, 'primary/pageone');
},
child: Text('To Page One'),
),
FlatButton(
onPressed: (){
Navigator.pushNamed(context, 'primary/pagethree');
},
child: Text('To Page Three'),
),
],
),
),
),
);
}
}
PrimaryThreeScreen.dart
class PrimaryThreeScreen extends StatelessWidget{
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Primary Page'),
),
body: Center(
child: Column(
children: <Widget>[
FlatButton(
onPressed: (){
Navigator.pushNamed(context, 'primary/pageone');
},
child: Text('To Page One'),
),
FlatButton(
onPressed: (){
Navigator.pushNamed(context, 'primary/pagetwo');
},
child: Text('To Page Two'),
)
],
),
),
);
}
}
如何仅在嵌套导航器上弹出?
谢谢!
解决方案
当按下后退按钮时,我认为它会使用你的应用程序的主导航器,因为它不知道你想要与之交互的嵌套导航器。
要解决它,您必须为导航器分配一个键,以便以后能够使用它。并在您使用嵌套导航器处理用户操作的小部件处添加 WillPopScope。
根据您的示例,我添加了一些代码。注意,maybePop() 函数将调用嵌套导航器小部件的 WillPopScope。如果你调用 pop(),它会直接弹出,忽略你的 widget 的 WillPopScope。
class PrimaryScreen extends StatelessWidget{
final _navigatorKey = GlobalKey<NavigatorState>();
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
if (_navigatorKey.currentState != null) {
_navigatorKey.currentState!.maybePop();
return false;
}
return true;
},
child: Navigator(
key: _navigatorKey,
initialRoute: 'primary/pageone',
onGenerateRoute: (RouteSettings settings) {
WidgetBuilder builder;
switch(settings.name){
case 'primary/pageone' :
builder = (BuildContext _) => PrimaryOneScreen();
break;
case 'primary/pagetwo' :
builder = (BuildContext _) => PrimaryTwoScreen();
break;
case 'primary/pagethree' :
builder = (BuildContext _) => PrimaryThreeScreen();
break;
default :
throw Exception('Invalid route: ${settings.name}');
}
return MaterialPageRoute(
builder: builder,
settings: settings
);
},
),
);
}
}
推荐阅读
- unity3d - 保存数据,关于关闭 UI
- typescript - 在 Typescript 类中获取另一个字段的类型
- java - 需要帮助排序 ArrayList 和计算测试分数的平均值
- reactjs - 基于子组件有条件地渲染包装代码
- javascript - 是否可以在 Windows 10 的 Windows 网络上远程获取触摸屏设备的当前坐标 X、Y?
- python - 用于 juputer notebook 的 Handcalcs 插件中的平方根问题
- javascript - Rijndael encryption VB to Javascript
- wordpress - 基于 ACF 转发器子字段自定义分类的查询帖子
- audio - 有没有办法在 C# 中创建虚拟扬声器或麦克风?
- python - 在对数据集进行预处理时,机器学习中的 Standard Scaler 和 MinMax Scaler 之间的主要区别是什么?