美文网首页
2023-06-14 深入理解Flutter中的Navigato

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

作者: 我是小胡胡分胡 | 来源:发表于2023-06-13 11:38 被阅读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包裹的组件层级结构:

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

    相关文章

      网友评论

          本文标题:2023-06-14 深入理解Flutter中的Navigato

          本文链接:https://www.haomeiwen.com/subject/xfscydtx.html