简介:

Flutter中,导航器(Navigator)是管理应用程序中不同页面之间跳转的要害组件之一。其间的Navigator.of(context)办法用于获取当前上下文(context)所在的导航器状况(NavigatorState),从而完成页面之间的导航操作。但是,有时候在运用Navigator.of(context)办法时会遇到反常,本文将解释这个反常的原因并供给解决办法。

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) { 
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: OutlinedButton(
              onPressed: () {
                Navigator.of(context).push(MaterialPageRoute(builder: (context) => SecondPage()));
              },
              child: Text('跳转')),
        ),
      ),
    );
  }
}

反常情况:

当运用Navigator.of(context)办法时,有时会抛出以下反常信息:

======== Exception caught by gesture ===============================================================
The following assertion was thrown while handling a gesture:
Navigator operation requested with a context that does not include a Navigator.
The context used to push or pop routes from the Navigator must be that of a widget that is a descendant of a Navigator widget.
When the exception was thrown, this was the stack: 

该反常信息提示了咱们运用Navigator.of(context)办法的上下文(context)必须是导航器(Navigator)的子级组件的上下文。

解决办法:

为了解决这个反常,咱们需要保证调用Navigator.of(context)办法的上下文(context)是导航器(Navigator)的子级组件。下面是一个示例代码,演示了如何正确运用Navigator.of(context)办法:

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) { //context
    return MaterialApp(
      home: FirstPage(),
    );
  }
}
class FirstPage extends StatelessWidget {
  const FirstPage({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: OutlinedButton(
          onPressed: () {
            Navigator.of(context).push(MaterialPageRoute(builder: (context) => SecondPage()));
          },
          child: Text('跳转'),
        ),
      ),
    );
  }
}
class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(),
      body: Center(
        child: Text('second page'),
      ),
    );
  }
}

现在,在FirstPage组件中,Navigator.of(context)办法将会正常工作,由于contextFirstPage组件的上下文,而且FirstPage是作为MaterialApp的子组件存在的。

探求Navigator.of(context)源码: 为了更深入地了解Navigator.of(context)办法的工作原理,咱们来看一下其源码完成:

static NavigatorState of(
  BuildContext context, {
  bool rootNavigator = false,
}) {
  NavigatorState? navigator;
  if (context is StatefulElement && context.state is NavigatorState) {
    navigator = context.state as NavigatorState;
  }
  if (rootNavigator) {
    navigator = context.findRootAncestorStateOfType<NavigatorState>() ?? navigator;
  } else {
    navigator = navigator ?? context.findAncestorStateOfType<NavigatorState>();
  }
  assert(() {
    if (navigator == null) {
      throw FlutterError(
        'Navigator operation requested with a context that does not include a Navigator.\n'
        'The context used to push or pop routes from the Navigator must be that of a '
        'widget that is a descendant of a Navigator widget.',
      );
    }
    return true;
  }());
  return navigator!;
}

从源码中可以看到,Navigator.of(context)办法首先查看上下文(context)是否是一个有状况组件(StatefulElement)且其状况(state)是NavigatorState类型,假如是,那么该上下文的导航器状况便是咱们要获取的。接着,假如rootNavigator参数为true,则继续查找最近的根级导航器状况;假如rootNavigator参数为false,则继续查找最近的导航器状况。最后,假如没有找到导航器状况,则抛出反常。

在上述示例中,Navigator.of(context)办法的可用性还与MaterialApp的层级结构有关。下面是MaterialApp包裹的组件层级结构:

  • MaterialApp (_MaterialAppState)
    • WidgetsApp (_WidgetsAppState)
      • Navigator (NavigatorState)
class MaterialApp extends StatefulWidget {
State<MaterialApp> createState() => _MaterialAppState();
Widget _buildWidgetApp(BuildContext context) {
WidgetsApp
State<WidgetsApp> createState() => _WidgetsAppState();
Widget build(BuildContext context) {
Navigator(
        restorationScopeId: 'nav',
        key: _navigator,
        initialRoute: _initialRouteName,
        onGenerateRoute: _onGenerateRoute,
        onGenerateInitialRoutes: widget.onGenerateInitialRoutes == null
          ? Navigator.defaultGenerateInitialRoutes
          : (NavigatorState navigator, String initialRouteName) {
            return widget.onGenerateInitialRoutes!(initialRouteName);
          },
        onUnknownRoute: _onUnknownRoute,
        observers: widget.navigatorObservers!,
        reportsRouteUpdateToEngine: true,
      )
class Navigator extends StatefulWidget {
NavigatorState createState() => NavigatorState();
class NavigatorState extends State<Navigator> with TickerProviderStateMixin, RestorationMixin {

在这个层级结构中,MaterialApp是一个StatefulWidget,它创建了一个_MaterialAppState的状况。_MaterialAppState进一步创建了一个WidgetsApp组件,也是一个StatefulWidget,并同享相同的状况_WidgetsAppState。在WidgetsApp中,又创建了一个Navigator组件,它的状况是NavigatorState

因此,Navigator.of(context)办法实际上是通过上下文(context)向上查找最近的NavigatorState状况对象,以便进行页面导航操作。

定论:

在运用Navigator.of(context)办法时,咱们需要保证调用它的上下文(context)是导航器(Navigator)的子级组件,以避免抛出反常。这样,咱们就可以在Flutter应用程序中轻松完成页面之间的导航操作。

希望本文对您了解和运用Navigator.of(context)办法有所帮助!假如您有任何问题或疑问,请随时发问。