RouterDelegate 不会根据侦听器 Fluter 的更改进行重建

RouterDelegate won't rebuild upon changes from listener Fluter

我正尝试按照 https://github.com/carloshwa/flutter-example/tree/navigator_2 中的示例切换到 Navigator 2.0,使其适应我的代码。

如示例中所示,我有一个 class AppState extends ChangeNotifier RouterDelegate

AppRouterDelegate() : navigatorKey = GlobalKey<NavigatorState>() {
    appState.addListener(notifyListeners);
    print('appState.addListener(notifyListeners) called');
  }

构建正确的页面

pages: [MaterialPage(child: WebPageMainLayout(appState: appState,))],

其中 WebPageMainLayout 添加一个 ConstrainedBox 并将 WebsitePageDisplay 作为其子项。

WebsitePageDisplay 有一个 Column.

第一个 Column 的小部件是 NavigationBar,从中设置按钮 AppStateselectedPage

void _handlePageTapped(String selected) {
    print('selected tapped is $selected');
    appState.selectedPage = selected;
  }

...

NavigationBarButton(
                title: AppLocalizations.instance.text('For retailers'),
                navigationPath: RetailersLandingRoute,
                onPressed: () {},
                onTapped: _handlePageTapped,
              ),

所以一旦设置它就会通知他的听众 (RouterDelegate)。

第二个 Column 的小部件是要显示的从 AppStateselectedWidget getter.

返回的实际页面
return Column(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: <Widget>[
        NavigationBar(),
        Expanded(
          child: widget.appState.selectedWidget,
        )
      ],
    );

问题是当按下按钮时,第二个小部件(来自 AppState 的 getter)没有被交换,面团我从 _handlePageTapped 得到正确的打印(例如.`/上面代码中的零售商)

我不确定是不是 RouterDelegate 那个面团,它收到了 AppState 中更改的通知,没有用新页面重建 Navigator,或者我只是实施错误的逻辑,因为我是 ChangeNotifier 和 Navigator 2.0 的新手,似乎有点过于复杂。

当页面首次加载时,我看到了我从 parseRouteInformationcurrentConfigurationrestoreRouteInformationsetNewRoutePath' first with no value ( as I don't have a /route ) but then with the correct/ 设置的打印集骑车人的价值。

AppRouteInformationParser.parseRouteInformation called for /
AppRouteInformationParser uri is /
AppRouteInformationParser.urlSegment switch: /
RouterDelegate.currentConfiguration appState.selectedPage is 
AppRouteInformationParser.restoreRouteInformation called for configuration 
RouterDelegate.setNewRoutePath configuration is Configuration {unknown: false, selectedPage: /cyclists}
AppState setting selectedPage to /cyclists
RouterDelegate.currentConfiguration appState.selectedPage is /cyclists
AppRouteInformationParser.restoreRouteInformation called for configuration /cyclists
restoreRouteInformation RouteInformation.location: /cyclists
RouterDelegate.currentConfiguration appState.selectedPage is /cyclists
AppRouteInformationParser.restoreRouteInformation called for configuration /cyclists
restoreRouteInformation RouteInformation.location: /cyclists
RouterDelegate.currentConfiguration appState.selectedPage is /cyclists
AppRouteInformationParser.restoreRouteInformation called for configuration /cyclists
restoreRouteInformation RouteInformation.location: /cyclists

但是当我按下 NavigationBar 的按钮时,我只得到 _handlePageTapped 打印。 在 chrome 中更改 Url 也不起作用.. 你能发现我做错了什么吗?一如既往,非常感谢您的帮助。

应用状态

class AppState extends ChangeNotifier {
  String _selectedPage;
  AppState() : _selectedPage = '';

  String get selectedPage => _selectedPage;

  // works
  Widget get selectedWidget {
    switch (selectedPage) {
      case CyclistsLandingRoute:
        return CyclistLanding();
        break;
      case RetailersLandingRoute:
        return RetailerLanding();
        break;
      case MapRoute:
        return CityMap();
        break;
      case AboutRoute:
        return AboutUs();
        break;
      case TermsOfServiceRoute:
        return TermsOfService();
        break;
      case PrivacyPolicyRoute:
        return PrivacyPolicy();
        break;
      // case PrivacySettingsRoute:
      //   return PrivacyPolicySettings();
      //   break;
      case CommunityGuidelinesRoute:
        return CommunityGuidelines();
        break;
      case LegalNoticeRoute:
        return LegalNotice();
        break;
      default:
        return CyclistLanding();
    }
  }

  set selectedPage(String page) {
    print('AppState setting selectedPage to $page');
    _selectedPage = page;
    notifyListeners();
  }
}

路由器代理

class AppRouterDelegate extends RouterDelegate<Configuration>
    with ChangeNotifier, PopNavigatorRouterDelegateMixin<Configuration> {
  final GlobalKey<NavigatorState> navigatorKey;
  AppState appState = AppState();
  AppRouterDelegate() : navigatorKey = GlobalKey<NavigatorState>() {
    appState.addListener(notifyListeners);
    print('appState.addListener(notifyListeners) called');
  }


  @override
  Configuration get currentConfiguration {

    print(
        'RouterDelegate.currentConfiguration appState.selectedPage is ${appState.selectedPage}');
    switch (appState.selectedPage) {
      case CyclistsLandingRoute:
        return Configuration.cyclists(appState.selectedPage);
        break;
      case RetailersLandingRoute:
        return Configuration.retailers(appState.selectedPage);
        break;
      case MapRoute:
        return Configuration.map(appState.selectedPage);
        break;
      case AboutRoute:
        return Configuration.about(appState.selectedPage);
      case TermsOfServiceRoute:
        return Configuration.termsOfService(appState.selectedPage);
      case PrivacyPolicyRoute:
        return Configuration.privacyPolicy(appState.selectedPage);
        break;
      // case PrivacySettingsRoute:
      //   return Configuration.privacySettings();
      //   break;
      case CommunityGuidelinesRoute:
        return Configuration.communityGuidelines(appState.selectedPage);
        break;
      case LegalNoticeRoute:
        return Configuration.legalNotice(appState.selectedPage);
        break;
      default:
        return Configuration.cyclists(appState.selectedPage);
    }
  }

  @override
  Widget build(BuildContext context) {
    return Navigator(
      key: navigatorKey,
      pages: [
        MaterialPage(
            child: WebPageMainLayout(
          appState: appState,
        ))
      ],
      onPopPage: (route, result) {
        if (!route.didPop(result)) return false;
        if (appState.selectedPage != null) {
          appState.selectedPage = null;
          notifyListeners();
        }

        // show404 = false;
        notifyListeners();
        return true;
      },
    );
  }

  @override
  Future<void> setNewRoutePath(Configuration configuration) async {
    print(
        'RouterDelegate.setNewRoutePath configuration is ${configuration.toString()}');

    if (configuration.isUnknown) {
      // show404 = true;
      appState.selectedPage = null;
      notifyListeners();
      return;
    } else if (configuration.isCyclist) {
      appState.selectedPage = configuration.selectedPage;
      notifyListeners();
      return;
    } else if (configuration.isRetailer) {
      appState.selectedPage = configuration.selectedPage;
      notifyListeners();
      return;
    } else if (configuration.isMap) {
      appState.selectedPage = configuration.selectedPage;
      notifyListeners();
      return;
    } else if (configuration.isAbout) {
      appState.selectedPage = configuration.selectedPage;
      notifyListeners();
      return;
    } else if (configuration.isTermsOfService) {
      appState.selectedPage = configuration.selectedPage;
      notifyListeners();
      return;
    } else if (configuration.isPrivacyPolicy) {
      appState.selectedPage = configuration.selectedPage;
      notifyListeners();
      return;
    } else if (configuration.isPrivacySettings) {
      appState.selectedPage = configuration.selectedPage;
      notifyListeners();
      return;
    } else if (configuration.isCommunityGuidelines) {
      appState.selectedPage = configuration.selectedPage;
      notifyListeners();
      return;
    } else if (configuration.isLegalNotice) {
      appState.selectedPage = configuration.selectedPage;
      notifyListeners();
      return;
    }
    return;
  }
}

配置

class Configuration {
  final bool unknown;
  final String selectedPage;

  Configuration.cyclists(this.selectedPage) : unknown = false;
  Configuration.retailers(this.selectedPage) : unknown = false;
  Configuration.map(this.selectedPage) : unknown = false;
  Configuration.about(this.selectedPage) : unknown = false;
  Configuration.termsOfService(this.selectedPage) : unknown = false;
  Configuration.privacyPolicy(this.selectedPage) : unknown = false;
  Configuration.privacySettings(this.selectedPage) : unknown = false;
  Configuration.communityGuidelines(this.selectedPage) : unknown = false;
  Configuration.legalNotice(this.selectedPage) : unknown = false;

  // bool get isHome => unknown == false;
  bool get isCyclist =>
      selectedPage == CyclistsLandingRoute; //unknown == false;
  bool get isRetailer =>
      selectedPage == RetailersLandingRoute; //unknown == false;
  bool get isMap => selectedPage == MapRoute; //unknown == true;
  bool get isAbout => selectedPage == AboutRoute; //unknown == false;
  bool get isTermsOfService =>
      selectedPage == TermsOfServiceRoute; //unknown == false;
  bool get isPrivacyPolicy =>
      selectedPage == PrivacyPolicyRoute; //unknown == false;
  bool get isPrivacySettings =>
      selectedPage == PrivacySettingsRoute; //unknown == false;
  bool get isCommunityGuidelines =>
      selectedPage == CommunityGuidelinesRoute; //unknown == false;
  bool get isLegalNotice =>
      selectedPage == LegalNoticeRoute; //unknown == false;
  bool get isUnknown => unknown == true;

  @override
  String toString() =>
      'Configuration {unknown: $unknown, selectedPage: $selectedPage}';
}

解析器

class AppRouteInformationParser extends RouteInformationParser<Configuration> {
  @override
  Future<Configuration> parseRouteInformation(
      RouteInformation routeInformation) async {
    print(
        'AppRouteInformationParser.parseRouteInformation called for ${routeInformation.location}');

    final Uri uri = Uri.parse(routeInformation.location);
    print('AppRouteInformationParser uri is $uri');

    switch (routeInformation.location) {
      case '/':
        print('AppRouteInformationParser.urlSegment switch: /');
        return Configuration.cyclists(CyclistsLandingRoute);
        break;
      case CyclistsLandingRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: cyclists');
        return Configuration.cyclists(CyclistsLandingRoute);
        break;
      case RetailersLandingRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: retailers');
        return Configuration.retailers(RetailersLandingRoute);
        break;
      case MapRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: map');
        return Configuration.map(MapRoute);
        break;
      case AboutRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: about');
        return Configuration.about(AboutRoute);
        break;
      case TermsOfServiceRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: terms-of-service');
        return Configuration.termsOfService(TermsOfServiceRoute);
        break;
      case PrivacyPolicyRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: privacy-policy');
        return Configuration.privacyPolicy(PrivacyPolicyRoute);
        break;
      case PrivacySettingsRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: privacy-settings');
        return Configuration.privacySettings(PrivacySettingsRoute);
        break;
      case CommunityGuidelinesRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: community-guidelines');
        return Configuration.communityGuidelines(CommunityGuidelinesRoute);
        break;
      case LegalNoticeRoute:
        print(
            'AppRouteInformationParser.routeInformation.location switch case: legal-notice');
        return Configuration.legalNotice(LegalNoticeRoute);
        break;

      default:
        print('AppRouteInformationParser.routeInformation.location: home');
        return Configuration.cyclists(CyclistsLandingRoute);
      // return Configuration.home();
    }
  }

  @override
  RouteInformation restoreRouteInformation(Configuration configuration) {

    print(
        'AppRouteInformationParser.restoreRouteInformation called for configuration ${configuration.selectedPage}');
    RouteInformation information = RouteInformation(location: '/cyclists');

    // if (configuration.isHome) {
    //   information = RouteInformation(location: '/');
    // } else
    if (configuration.isCyclist) {
      print('restoreRouteInformation RouteInformation.location: /cyclists');
      information = RouteInformation(location: '/cyclists');
    } else if (configuration.isRetailer) {
      print('restoreRouteInformation RouteInformation.location: /retailers');
      information = RouteInformation(location: '/retailers');
    } else if (configuration.isMap) {
      print('restoreRouteInformation RouteInformation.location: /map');
      information = RouteInformation(location: '/map');
    } else if (configuration.isAbout) {
      print('restoreRouteInformation RouteInformation.location: /about');
      information = RouteInformation(location: '/about');
    } else if (configuration.isTermsOfService) {
      print(
          'restoreRouteInformation RouteInformation.location: /terms-of-service');
      information = RouteInformation(location: '/terms-of-service');
    } else if (configuration.isPrivacyPolicy) {
      print(
          'restoreRouteInformation RouteInformation.location: /privacy-policy');
      information = RouteInformation(location: '/privacy-policy');
    } else if (configuration.isPrivacySettings) {
      print(
          'restoreRouteInformation RouteInformation.location: /privacy-settings');
      information = RouteInformation(location: '/privacy-settings');
    } else if (configuration.isCommunityGuidelines) {
      print(
          'restoreRouteInformation RouteInformation.location: /community-guidelines');
      information = RouteInformation(location: '/community-guidelines');
    } else if (configuration.isLegalNotice) {
      print('restoreRouteInformation RouteInformation.location: /legal-notice');
      information = RouteInformation(location: '/legal-notice');
    }
    // else if (configuration.isUnknown) {
    // information = RouteInformation(location: '/unknown');
    // }

    return information;
  }
}

终于找到我错的地方了.. 我在一些小部件 (NavigationBar) 中实例化了一个新的 AppState,而不是从 RouterDelegate 传递一个。 更正后,它会按预期工作。 我猜是专注于新的 Navigator 2.0 系统让我的大脑变成了新手哈哈。