Arc*_*nes 9 flutter flutter-navigation
当我有Nested时,我遇到了这个问题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'),
),
],
),
);
}
}
Run Code Online (Sandbox Code Playgroud)
如您所见,我从Navigator提供的“最热门”开始导航,然后转到MaterialApp孩子Navigator的'two/nextpage',然后转到MaterialApp '/three'。问题在于,这样做onPressed: () => Navigator.of(context).pushNamed('/three'),返回Navigator的电流context是孩子Navigator。我需要访问MaterialApp的Navigator导航正确。什么是正确的方法?
另外,如何处理Navigator我要访问的情况位于Navigators 堆栈中间的某个位置?
Rém*_*let 13
大多数情况下,您只有2个导航器。
这意味着要获取嵌套的,请执行以下操作:
Navigator.of(context)
Run Code Online (Sandbox Code Playgroud)
并获取根目录,请执行以下操作:
Navigator.of(context, rootNavigator: true)
Run Code Online (Sandbox Code Playgroud)
对于更复杂的体系结构,到目前为止,最简单的方法是使用GlobalKey(因为在构建过程中您永远不会阅读Navigator )
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,
),
);
}
}
Run Code Online (Sandbox Code Playgroud)
然后可以使用这种方式:
key.currentState.pushNamed('foo')
Run Code Online (Sandbox Code Playgroud)
实际上,Navigator当您有子导航流或内部旅程时,您必须使用嵌套。请阅读嵌套导航器的文档。
但是,要访问根导航器,您可以Navigator从 current递归查找父级,Navigator并Navigator在没有 parent 时返回 current Navigator。
例子:
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);
Run Code Online (Sandbox Code Playgroud)
编辑:
解决方案1:
要获得特定的父级Navigator,我可以考虑扩展当前Navigator类以接受 anid并找到Navigatorby 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;
}
}
Run Code Online (Sandbox Code Playgroud)
使用NavigatorWithId而不是Navigator在需要时使用,例如
return NavigatorWithId(
id: 1,
initialRoute: '/',
onGenerateRoute: (_) =>
MaterialPageRoute<dynamic>(builder: (_) => const YourPage()),
)
Run Code Online (Sandbox Code Playgroud)
然后像这样访问它:
NavigatorWithId.of(context, id: 1)
Run Code Online (Sandbox Code Playgroud)
解决方案2:
传递ValueKey给导航器并创建一个 util 函数来匹配 key 并返回所需的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;
}
}
Run Code Online (Sandbox Code Playgroud)
用
return Navigator(
key: const ValueKey<String>('Navigator1'),
initialRoute: '/',
onGenerateRoute: (_) =>
MaterialPageRoute<void>(builder: (_) => const RootPage()),
);
Run Code Online (Sandbox Code Playgroud)
并像访问它一样访问它
getNavigator(context, key: const ValueKey<String>('Navigator1'))
Run Code Online (Sandbox Code Playgroud)
我可以看到这种方法的缺点是并非所有类型的密钥都受支持。
注意:我不认为上述任何解决方案是最好的或最优的。这是我想出的几种方法。如果有人能想出更好的方法,我很想学习:)
希望这可以帮助!
| 归档时间: |
|
| 查看次数: |
1456 次 |
| 最近记录: |