Flutter Navigator2.0的原理和Web端实践

01

背景与动机

Navigator 2.0推出之前,Flutter主要通过Navigator 1.0和其提供的 API(如push()pop()pushNamed()等)来管理页面路由。然而,Navigator 1.0存在一些局限性,如难以实现复杂的页面操作(如移除栈内中间页面、交换页面等)、不支持嵌套路由以及无法满足全平台(尤其是Web平台)的新需求。因此,Flutter官方团队决定对路由系统进行改造,推出了Navigator 2.0。 

02

主要特性

  • 声明式API Navigator 2.0提供的声明式API使得路由管理更加直观和易于理解。开发者只需声明页面的配置信息,而无需编写复杂的导航逻辑代码。这种方式不仅减少了代码量,还提高了代码的可读性和可维护性。

  • 嵌套路由 Navigator 2.0满足了嵌套路由的需求场景,允许开发者在应用中创建嵌套的路由结构。这使得应用的结构更加清晰,同时也提高了页面导航的灵活性。

  • 全平台支持 Navigator 2.0提供的API能够满足不同平台(如iOSAndroidWeb等)的导航需求,使得开发者能够更加方便地构建跨平台的应用。

  • 强大的页面操作能力 Navigator 2.0提供了更加丰富的页面操作能力,如移除栈内中间页面、交换页面等。这些操作在Navigator 1.0中很难实现或需要编写复杂的代码,而在Navigator 2.0中则变得简单直接。

03

核心组件

  • Router 在Navigator 2.0中,Router组件是路由管理的核心。它负责根据当前的路由信息(RouteInformation)和路由信息解析器(RouteInformationParser)来构建和更新UIRouter组件接收三个主要参数:

    1.routeInformationProvider:提供当前的路由信息;

    2.routeInformationParser:将路由信息解析为路由配置;

    3.routerDelegate:根据路由配置构建和更新UI

  • RouteInformationProvider RouteInformationProvider是一个提供当前路由信息的组件。它通常与平台相关的路由信息源(如浏览器的URLAndroidIntent等)集成,以获取当前的路由信息。

  • RouteInformationParser RouteInformationParser负责将RouteInformation解析为RouteConfiguration。这个过程允许开发者根据路由信息的格式(如URL)来定义如何将其映射到应用内的路由配置。

  • RouterDelegate RouterDelegate是与UI构建紧密相关的组件。它必须实现RouterDelegate接口,并提供两个主要方法: 

    1.build(BuildContext context):根据当前的路由配置构建UI

    2.setNewRoutePath(List configuration):设置新的路由路径,并更新UI

    3.Future popRoute() :实现后退逻辑。

04

简单实例

首先通过MaterialApp.router()来创建MaterialApp:

class MyApp extends StatelessWidget {  
  @override  
  Widget build(BuildContext context) {  
    final routerDelegate = MyRouterDelegate();  
    final routeInformationParser = MyRouteInformationParser();  
  
    return MaterialApp.router(  
      title: 'Flutter Navigator 2.0 Demo',  
      theme: ThemeData(  
        primarySwatch: Colors.blue,  
      ),  
      routerDelegate: routerDelegate,  
      routeInformationParser: routeInformationParser,  
    );  
  }  
}

需要定义一个RouterDelegate对象和一个RouteInformationParser对象。其中根据路由配置构建和更新UIRouteInformationParser负责将RouteInformation解析为RouteConfiguration。 RouterDelegate可以传个泛型,定义其currentConfiguration对象的类型。

class MyRouterDelegate extends RouterDelegate<String>  
  with PopNavigatorRouterDelegateMixin<String>, ChangeNotifier {  
  final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();  
  private List<String> _pages = ['/home'];  
  
  @override  
  Widget build(BuildContext context) {  
    return Navigator(  
      key: navigatorKey,  
      pages: _pages.map((route) => MaterialPage(  
        key: Key(route),  
        child: generatePage(route),  
      )).toList(),  
      onPopPage: (route, result) {  
        if (!route.didPop(result)) {  
          return false;  
        }  
  
        _pages.removeLast();  
        notifyListeners();  
        return true;  
      },  
    );  
  }  
  
  @override  
  Future<void> setNewRoutePath(String path) async {  
    if (!_pages.contains(path)) {  
      _pages.add(path);  
      notifyListeners();  
    }  
  }  
  
  Widget generatePage(String route) {  
    switch (route) {  
      case '/home':  
        return HomePage();  
      case '/details':  
        // 这里可以传递参数,例如 DetailsPage(arguments: someData)  
        return DetailsPage();  
      default:  
        return NotFoundPage();  
    }  
  }  
  
  @override  
  String get currentConfiguration => _pages.last;  
}

其中build()一般返回的是一个Navigator对象,popRoute()实现后退逻辑,setNewRoutePath()实现新页面的逻辑。定义了一个_pages数组对象,记录每个路由的path,可以理解为是一个路由栈,这个路由栈对我们来说非常友好,在有复杂的业务逻辑时,我们可以自行定义相应的栈管理逻辑。currentConfiguration返回的是栈顶的page信息。创建一个类继承RouteInformationParser,主要的作用是包装解析路由信息,这里有一个最简单的方式,如下:

class MyRouteInformationParser extends RouteInformationParser<String> {  
  @override  
  Future<String> parseRouteInformation(RouteInformation routeInformation) {  
    final uri = Uri.parse(routeInformation.location);  
    return SynchronousFuture(uri.path);  
  }  
  
  @override  
  RouteInformation restoreRouteInformation(String configuration) {  
    return RouteInformation(location: configuration);  
  }  
}

好的,接下来我们看一下调用:

class HomePage extends StatelessWidget {  
  @override  
  Widget build(BuildContext context) {  
    return Scaffold(  
      appBar: AppBar(title: Text('Home')),  
      body: Center(  
        child: ElevatedButton(  
          onPressed:&
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值