2023-06-14 深入理解Flutter中的Navigato

2023-06-13  本文已影响0人  我是小胡胡分胡

简介:

在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包裹的组件层级结构:

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)方法有所帮助!如果您有任何问题或疑问,请随时提问。

上一篇下一篇

猜你喜欢

热点阅读