美文网首页
2023-04-03 Flutter导航Navigator原理

2023-04-03 Flutter导航Navigator原理

作者: 我是小胡胡123 | 来源:发表于2023-04-02 16:46 被阅读0次

Flutter导航Navigator

https://developer.aliyun.com/article/918784

onPressed: () {
  Navigator.of(context).push(
    MaterialPageRoute(
      builder: (context) => const SongScreen(song: song),
    ),
  );
},
child: Text(song.name),

StatefullWidget:

  • MaterialApp、_MaterialAppState
  • WidgetsApp、_WidgetsAppState
  • Navigator 、NavigatorState
  • Router、_RouterState
    MaterialApp包裹Navigator,通过 Navigator.of(context)方法查找最近的祖先 NavigatorState

1、 MaterialApp

MaterialApp

class MaterialApp extends StatefulWidget {
  @override
  State<MaterialApp> createState() => _MaterialAppState();
}

_MaterialAppState

Widget build(BuildContext context) {
    Widget result = _buildWidgetApp(context);
    result = Focus(
      canRequestFocus: false,
      onKey: (FocusNode node, RawKeyEvent event) {
        if (event is! RawKeyDownEvent || event.logicalKey != LogicalKeyboardKey.escape)
          return KeyEventResult.ignored;
        return Tooltip.dismissAllToolTips() ? KeyEventResult.handled : KeyEventResult.ignored;
      },
      child: result,
    );


    return ScrollConfiguration(
      behavior: widget.scrollBehavior ?? const MaterialScrollBehavior(),
      child: HeroControllerScope(
        controller: _heroController,
        child: result,
      ),
    );
  }

_buildWidgetApp

  Widget _buildWidgetApp(BuildContext context) { 
    final Color materialColor = widget.color ?? widget.theme?.primaryColor ?? Colors.blue;
    if (_usesRouter) {
      return WidgetsApp.router(
        key: GlobalObjectKey(this),
        routeInformationProvider: widget.routeInformationProvider, 
//其他省略
      );
    }

    return WidgetsApp(
      key: GlobalObjectKey(this),
      navigatorKey: widget.navigatorKey,
      navigatorObservers: widget.navigatorObservers!,
      pageRouteBuilder: <T>(RouteSettings settings, WidgetBuilder builder) {
        return MaterialPageRoute<T>(settings: settings, builder: builder);
      }, 
//其他省略
    );
  }

创建子widget,类型为 WidgetsApp

2、WidgetsApp

WidgetsApp

class WidgetsApp extends StatefulWidget {
  State<WidgetsApp> createState() => _WidgetsAppState();
}

_WidgetsAppState

class _WidgetsAppState extends State<WidgetsApp> with WidgetsBindingObserver {
  @override
  Widget build(BuildContext context) {
    Widget? routing;
    if (_usesRouter) {
         routing = Router<Object>(
        restorationScopeId: 'router',
        routeInformationProvider: _effectiveRouteInformationProvider,
        routeInformationParser: widget.routeInformationParser,
        routerDelegate: widget.routerDelegate!,
        backButtonDispatcher: widget.backButtonDispatcher,
      );
    } else if (_usesNavigator) {
      routing = 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,
      );
      );
    }

    Widget result;
    if (widget.builder != null) {
      result = Builder(
        builder: (BuildContext context) {
          return widget.builder!(context, routing);
        },
      );
    } else {
      assert(routing != null);
      result = routing!;
    }
 
    final Widget title;
 
    final Locale appLocale = widget.locale != null
      ? _resolveLocales(<Locale>[widget.locale!], widget.supportedLocales)
      : _locale!;

    assert(_debugCheckLocalizations(appLocale));

    Widget child = Localizations(
      locale: appLocale,
      delegates: _localizationsDelegates.toList(),
      child: title,
    );

    final MediaQueryData? data = MediaQuery.maybeOf(context);
    if (!widget.useInheritedMediaQuery || data == null) {
      child = MediaQuery.fromWindow(
        child: child,
      );
    }

    return RootRestorationScope(
      restorationId: widget.restorationScopeId,
      child: SharedAppData(
        child: Shortcuts(
          debugLabel: '<Default WidgetsApp Shortcuts>',
          shortcuts: widget.shortcuts ?? WidgetsApp.defaultShortcuts, 
          child: DefaultTextEditingShortcuts(
            child: Actions(
              actions: widget.actions ?? WidgetsApp.defaultActions,
              child: FocusTraversalGroup(
                policy: ReadingOrderTraversalPolicy(),
                child: child,
              ),
            ),
          ),
        ),
      ),
    );
  }

_WidgetsAppState

3、 Navigator

Navigator

class Navigator extends StatefulWidget {
  NavigatorState createState() => NavigatorState();
}

NavigatorState

  Widget build(BuildContext context) {

    return HeroControllerScope.none(
      child: Listener(
        onPointerDown: _handlePointerDown,
        onPointerUp: _handlePointerUpOrCancel,
        onPointerCancel: _handlePointerUpOrCancel,
        child: AbsorbPointer(
          absorbing: false, 
          child: FocusScope(
            node: focusScopeNode,
            autofocus: true,
            child: UnmanagedRestorationScope(
              bucket: bucket,
              child: Overlay(
                key: _overlayKey,
                initialEntries: overlay == null ?  _allRouteOverlayEntries.toList(growable: false) : const <OverlayEntry>[],
              ),
            ),
          ),
        ),
      ),
    );
  }

4、Router

Router也是一个statefullWidget


class Router<T> extends StatefulWidget {
  State<Router<T>> createState() => _RouterState<T>();
}

_RouterState

  Widget build(BuildContext context) {
    return UnmanagedRestorationScope(
      bucket: bucket,
      child: _RouterScope(
        routeInformationProvider: widget.routeInformationProvider,
        backButtonDispatcher: widget.backButtonDispatcher,
        routeInformationParser: widget.routeInformationParser,
        routerDelegate: widget.routerDelegate,
        routerState: this,
        child: Builder( 
          builder: widget.routerDelegate.build,
        ),
      ),
    );
  }

5、 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) {
 
      }
      return true;
    }());
    return navigator!;
  }

这段代码实现了一个静态方法 of,用于从一个 BuildContext 中获取对应的 NavigatorState。下面是这段代码的执行流程:

  • 定义一个 NavigatorState 类型的变量 navigator 并初始化为 null。
  • 如果传入的 BuildContext 是一个 StatefulElement,并且它的 state 是一个 NavigatorState,则将 navigator 赋值为该 NavigatorState。
  • 如果 rootNavigator 参数为 true,则通过 context.findRootAncestorStateOfType<NavigatorState>() 方法查找最近的祖先 NavigatorState,并将它赋值给 navigator。
  • 如果 rootNavigator 参数为 false,则通过 context.findAncestorStateOfType<NavigatorState>() 方法查找最近的祖先 NavigatorState,并将它赋值给 navigator。
  • 使用 assert() 方法进行断言,确保 navigator 不为空。如果为空,则抛出 FlutterError 异常。
  • 返回 navigator。

因此,这段代码的作用是从给定的 BuildContext 中获取对应的 NavigatorState,如果找不到则会抛出异常。同时,可以通过 rootNavigator 参数来指定是否查找根 NavigatorState。

6、NavigatorState

NavigatorState 类的handlePush方法
主要作用是

 void handlePush({ required NavigatorState navigator, required bool isNewFirst, required Route<dynamic>? previous, required Route<dynamic>? previousPresent }) {
    assert(currentState == _RouteLifecycle.push || currentState == _RouteLifecycle.pushReplace || currentState == _RouteLifecycle.replace);
    assert(navigator != null);
    assert(navigator._debugLocked);
    assert(
      route._navigator == null,
      'The pushed route has already been used. When pushing a route, a new '
      'Route object must be provided.',
    );
    final _RouteLifecycle previousState = currentState;
    route._navigator = navigator;
    route.install();
    assert(route.overlayEntries.isNotEmpty);
    if (currentState == _RouteLifecycle.push || currentState == _RouteLifecycle.pushReplace) {
      final TickerFuture routeFuture = route.didPush();
      currentState = _RouteLifecycle.pushing;
      routeFuture.whenCompleteOrCancel(() {
        if (currentState == _RouteLifecycle.pushing) {
          currentState = _RouteLifecycle.idle;
          assert(!navigator._debugLocked);
          assert(() { navigator._debugLocked = true; return true; }());
          navigator._flushHistoryUpdates();
          assert(() { navigator._debugLocked = false; return true; }());
        }
      });
    } else {
      assert(currentState == _RouteLifecycle.replace);
      route.didReplace(previous);
      currentState = _RouteLifecycle.idle;
    }
    if (isNewFirst) {
      route.didChangeNext(null);
    }

    if (previousState == _RouteLifecycle.replace || previousState == _RouteLifecycle.pushReplace) {
      navigator._observedRouteAdditions.add(
        _NavigatorReplaceObservation(route, previousPresent),
      );
    } else {
      assert(previousState == _RouteLifecycle.push);
      navigator._observedRouteAdditions.add(
        _NavigatorPushObservation(route, previousPresent),
      );
    }
  }

这段代码实现了 Navigator 对栈进行 push 或者 pushReplace 的操作,主要的实现逻辑如下:

  • 进行断言校验,包括当前状态、navigator 的状态以及被 push 的 route 的状态。
  • 将当前 route 的 _navigator 属性设置为传入的 navigator,并调用 install() 方法。
  • 如果当前状态为 push 或者 pushReplace,则会调用 route 的 didPush() 方法,并将 currentState 设置为 pushing。
  • 如果当前状态为 replace,则会调用 route 的 didReplace() 方法,并将 currentState 设置为 idle。
  • 如果 isNewFirst 为 true,则调用 route 的 didChangeNext() 方法。
  • 根据 previousState 的不同,将对应的 _NavigatorReplaceObservation 或者 _NavigatorPushObservation 对象加入到 navigator 的 _observedRouteAdditions 中。

总体来说,这段代码主要是实现了 Navigator 对栈进行 push 或者 pushReplace 的操作,并且在操作过程中还会调用 route 中的不同方法,以及在完成操作后会将对应的 observation 对象加入到 navigator 的 _observedRouteAdditions 中。

最终调用到 setState


image.png

7、处理侧滑返回手势

import 'package:flutter/material.dart';

class MyPage extends StatefulWidget {
  @override
  _MyPageState createState() => _MyPageState();
}

class _MyPageState extends State<MyPage> {
  @override
  Widget build(BuildContext context) {
    return WillPopScope(
      onWillPop: () async {
        // 当用户从屏幕边缘向右滑动时,onWillPop回调函数会被调用
        if (Navigator.of(context).canPop()) {
          Navigator.of(context).pop();
          return false;
        }
        return true;
      },
      child: Scaffold(
        appBar: AppBar(
          title: Text('My Page'),
        ),
        body: Center(
          child: Text('Hello, World!'),
        ),
      ),
    );
  }
}

相关文章

网友评论

      本文标题:2023-04-03 Flutter导航Navigator原理

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