【问题标题】:RouterDelegate won't rebuild upon changes from listener FluterRouterDelegate 不会根据侦听器 Fluter 的更改重建
【发布时间】:2022-01-04 00:52:03
【问题描述】:

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

在示例中,我有一个class AppState extends ChangeNotifierRouterDelegate 正在收听

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 的吸气剂)没有被交换,面团我从_handlePageTapped 得到正确的打印(例如,上面代码中的`/retailers)

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

当页面首次加载时,我会看到我设置的一组打印件,这些打印件来自 parseRouteInformationcurrentConfigurationrestoreRouteInformationsetNewRoutePath' first with no value ( as I don't have a /route ) but then with the correct/cyclists` 值。

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;
  }
}

【问题讨论】:

    标签: flutter flutter-web flutter-navigation flutter-change-notifier


    【解决方案1】:

    终于知道我错在哪里了。。 我在一些小部件(NavigationBar)中实例化了一个新的AppState,而不是从RouterDelegate传递那个。 更正后,它按预期工作。 我想专注于新的 Navigator 2.0 系统让我的大脑变得新手哈哈。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-03-22
      • 1970-01-01
      • 1970-01-01
      • 2012-11-29
      • 1970-01-01
      • 1970-01-01
      • 2021-05-23
      相关资源
      最近更新 更多