RouterDelegate 不会根据侦听器 Fluter 的更改重建
Posted
技术标签:
【中文标题】RouterDelegate 不会根据侦听器 Fluter 的更改重建【英文标题】:RouterDelegate won't rebuild upon changes from listener Fluter 【发布时间】:2022-01-04 00:52:03 【问题描述】:我正在尝试按照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
,从中设置按钮AppState
的selectedPage
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
的小部件是从AppState
的selectedWidget
getter 返回的实际页面。
return Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
NavigationBar(),
Expanded(
child: widget.appState.selectedWidget,
)
],
);
问题是,当按下按钮时,第二个小部件(来自AppState
的吸气剂)没有被交换,面团我从_handlePageTapped
得到正确的打印(例如,上面代码中的`/retailers)
我不确定是不是那个面团的 RouterDelegate,它会收到 AppState
更改的通知,不会用新页面重建 Navigator
,或者我只是在执行错误的逻辑,因为我我是 ChangeNotifier 的新手,Navigator 2.0 似乎有点过于复杂。
当页面首次加载时,我会看到我设置的一组打印件,这些打印件来自 parseRouteInformation
、currentConfiguration
、restoreRouteInformation
、setNewRoutePath' 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;
【问题讨论】:
【参考方案1】:终于知道我错在哪里了。。
我在一些小部件(NavigationBar
)中实例化了一个新的AppState
,而不是从RouterDelegate传递那个。
更正后,它按预期工作。
我想专注于新的 Navigator 2.0 系统让我的大脑变得新手哈哈。
【讨论】:
以上是关于RouterDelegate 不会根据侦听器 Fluter 的更改重建的主要内容,如果未能解决你的问题,请参考以下文章