当我嵌套Navigator
时遇到此问题。像这样
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: "/",
routes: {
'/': (context) => SomeOneView(),
'/two': (context) => SomeTwoView(),
'/three': (context) => SomeThreeView(),
},
);
}
}
class SomeOneView extends StatefulWidget {
@override
_SomeOneViewState createState() => _SomeOneViewState();
}
class _SomeOneViewState extends State<SomeOneView> {
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: double.infinity,
color: Colors.indigo,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MaterialButton(
color: Colors.white,
child: Text('Next'),
onPressed: () => Navigator.of(context).pushNamed('/two'),
),
],
),
);
}
}
class SomeTwoView extends StatefulWidget {
@override
_SomeTwoViewState createState() => _SomeTwoViewState();
}
class _SomeTwoViewState extends State<SomeTwoView> {
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
// Some implementation
},
child: Navigator(
initialRoute: "two/home",
onGenerateRoute: (RouteSettings settings) {
WidgetBuilder builder;
switch (settings.name) {
case "two/home":
builder = (BuildContext context) => HomeOfTwo();
break;
case "two/nextpage":
builder = (BuildContext context) => PageTwoOfTwo();
break;
}
return MaterialPageRoute(builder: builder, settings: settings);
},
),
);
}
}
class HomeOfTwo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: double.infinity,
color: Colors.white,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MaterialButton(
color: Colors.white,
child: Text('Next'),
onPressed: () => Navigator.of(context).pushNamed('two/nextpage'),
),
],
),
);
}
}
class PageTwoOfTwo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: double.infinity,
color: Colors.teal,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
MaterialButton(
child: Text('Next'),
onPressed: () => Navigator.of(context).pushNamed('/three'),
),
],
),
);
}
}
如您所见,我从Navigator
提供的最热门MaterialApp
导航到子Navigator
的{{1}},然后应转到{ {1}} 'two/nextpage'
。问题是执行MaterialApp
会返回当前'/three'
的{{1}},它是子onPressed: () => Navigator.of(context).pushNamed('/three'),
。我需要访问Navigator
的{{1}}才能正确导航。什么是正确的方法?
如果我要访问的context
位于Navigator
堆栈中间的某个地方,该如何处理?
答案 0 :(得分:3)
大多数时候,您只有2个导航器。
要获取嵌套的内容,请执行以下操作:
Navigator.of(context)
要获得根,请执行以下操作:
Navigator.of(context, rootNavigator: true)
对于更复杂的体系结构,到目前为止,最简单的方法是使用GlobalKey(因为您永远不会在 build 期间阅读导航器)
final GlobalKey<NavigatorState> key =GlobalKey();
final GlobalKey<NavigatorState> key2 =GlobalKey();
class Foo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
navigatorKey: key,
home: Navigator(
key: key2,
),
);
}
}
然后您可以使用这种方式:
key.currentState.pushNamed('foo')
答案 1 :(得分:1)
实际上,当您有子导航流程或内部旅程时,必须使用嵌套的Navigator
。请阅读nesting navigators的文档。
但是,要获得对根导航器的访问权限,您可以从当前Navigator
递归地查找父Navigator
,并在没有父Navigator
的情况下返回当前Navigator
。 / p>
示例:
NavigatorState getRootNavigator(BuildContext context) {
final NavigatorState state = Navigator.of(context);
try {
return getRootNavigator(state.context);
} catch (e) {
return state;
}
}
//use it from any widget like
getRootNavigator(context);
编辑:
解决方案1:
要获取特定的父级Navigator
,我可以考虑扩展当前的Navigator
类以接受id
并通过Navigator
找到id
。像这样:
class NavigatorWithId extends Navigator {
const NavigatorWithId(
{Key key,
@required this.id,
String initialRoute,
@required RouteFactory onGenerateRoute,
RouteFactory onUnknownRoute,
List<NavigatorObserver> observers = const <NavigatorObserver>[]})
: assert(onGenerateRoute != null),
assert(id != null),
super(
key: key,
initialRoute: initialRoute,
onGenerateRoute: onGenerateRoute,
onUnknownRoute: onUnknownRoute,
observers: observers,
);
// when id is null, the `of` function returns top most navigator
final int id;
static NavigatorState of(BuildContext context, {int id, ValueKey<String> key}) {
final NavigatorState state = Navigator.of(
context,
rootNavigator: id == null,
);
if (state.widget is NavigatorWithId) {
// ignore: avoid_as
if ((state.widget as NavigatorWithId).id == id) {
return state;
} else {
return of(state.context, id: id);
}
}
return state;
}
}
在需要时使用NavigatorWithId
代替Navigator
,例如
return NavigatorWithId(
id: 1,
initialRoute: '/',
onGenerateRoute: (_) =>
MaterialPageRoute<dynamic>(builder: (_) => const YourPage()),
)
然后按以下方式访问它:
NavigatorWithId.of(context, id: 1)
解决方案2:
将ValueKey
传递给导航器,并创建一个与键匹配的util函数,并返回所需的Navigator
。
类似的功能
NavigatorState getNavigator(BuildContext context, {bool rootNavigator = false, ValueKey<String> key}) {
assert(rootNavigator != null);
final NavigatorState state = Navigator.of(
context,
rootNavigator: rootNavigator,
);
if (rootNavigator) {
return state;
} else if (state.widget.key == key) {
return state;
}
try {
return getNavigator(state.context, key: key);
} catch (e) {
return state;
}
}
使用
return Navigator(
key: const ValueKey<String>('Navigator1'),
initialRoute: '/',
onGenerateRoute: (_) =>
MaterialPageRoute<void>(builder: (_) => const RootPage()),
);
并像访问它
getNavigator(context, key: const ValueKey<String>('Navigator1'))
我可以看到这种方法的缺点,因为并非所有类型的键都受支持。
注意:我不认为上述任何解决方案都是最佳或最优的。这些是我想出的几种方法。如果有人可以提出更好的方法,我很想学习:)
希望这会有所帮助!