flutter路由2.0 - Tue, Dec 1, 2020
1. 概述
flutter开始支持web页面,同时基于以前的路由1.0在web上会有问题。 由于web能够使用url直接定位到子页面,基于路由1.0是无法实现的。 所以有两种解决办法:
- 把浏览器url完全隐藏掉(google正在做)
- 支持url跳转子页面
2. 路由2.0
基于web页面,有两种时序。我们需要路由2.0的实现满足这两种时序
- 通过按钮点击进入子页面
- 通过url进入子页面
具体实现
2.1 状态管理
app_router.dart
AppState是路由状态管理器,维护一个全局的路由状态。
class AppState extends ChangeNotifier {
AppRoutePath _currentPath = RootPath();
AppRoutePath get currentPath => _currentPath;
set currentPath(AppRoutePath path) {
print('currentPath ${path.path}');
_currentPath = path;
notifyListeners();
}
}
2.2 路由管理
由于是全局状态,所以每个有路由迁移的页面都需要保存appState
appState作为RootPage(appState)
的参数进行了入参。
当appState发生变化时,会触发currentConfiguration的更新,重新描画页面。(时序1)
当从url切换页面时,会触发setNewRoutePath
切换新的页面(时序2)
class AppRouterDelegate extends RouterDelegate<AppRoutePath>
with ChangeNotifier, PopNavigatorRouterDelegateMixin<AppRoutePath> {
final GlobalKey<NavigatorState> navigatorKey;
AppState appState = AppState();
AppRouterDelegate() : navigatorKey = GlobalKey<NavigatorState>() {
appState.addListener(notifyListeners);
}
AppRoutePath get currentConfiguration {
print("currentConfiguration ${appState.currentPath}");
return appState.currentPath;
}
@override
Widget build(BuildContext context) {
return Navigator(
key: navigatorKey,
pages: [
MaterialPage(
child: RootPage(appState),
),
],
onPopPage: (route, result) {
if (!route.didPop(result)) {
return false;
}
return true;
},
);
}
@override
Future<void> setNewRoutePath(AppRoutePath path) async {
print("setNewRoutePath ${path.path}");
appState.currentPath = path;
}
}
root_page.dart
页面入参实例
class RootPage extends StatefulWidget {
final AppState appState;
RootPage(
this.appState,
);
@override
_RootPageState createState() => _RootPageState();
}
2.3 url转appState
parseRouteInformation
是url传过来的参数,通过解析参数初始化appState,进行页面的切换。
class AppRouteInformationParser extends RouteInformationParser<AppRoutePath> {
@override
Future<AppRoutePath> parseRouteInformation(RouteInformation routeInformation) async {
final uri = Uri.parse(routeInformation.location);
print('parseRouteInformation ${routeInformation.location}');
switch (uri.path) {
case Routes.home:
return HomePath();
case Routes.productList:
return ProductListPath();
case Routes.productDetail:
return ProductDetailPath(id: uri.queryParameters['id']);
case Routes.deviceList:
return DeviceListPath();
case Routes.deviceDetail:
return DeviceDetailPath();
case Routes.userList:
return UserListPath();
case Routes.userDetail:
return UserDetailPath();
case Routes.setting:
return SettingPath();
default:
return HomePath();
}
}
@override
RouteInformation restoreRouteInformation(AppRoutePath configuration) {
return RouteInformation(location: configuration.path);
}
}
3. 详细时序
3.1 时序1
- AppState.currentPath
- AppRouterDelegate.currentConfiguration
3.2 时序2
- AppRouteInformationParser.parseRouteInformation
- AppRouterDelegate.setNewRoutePath
- AppState.currentPath
- AppRouterDelegate.currentConfiguration