702 字
4 分钟
Flutter Navigator v2
2025-05-07

Navigator 2.0(也称为 Router API),它与传统的 imperative(命令式)Navigator 1.0 不同,采用声明式的思路,更好地支持 URL 路由、Web 与桌面多窗口,以及深度链接。

概念#

  1. Router 顶层 Widget,负责接收外部路由变化(如浏览器地址栏、系统返回、深度链接)并将它们分发给下面的两个组件:
    • RouteInformationParser
    • RouterDelegate
  2. RouteInformationParser 把外部的 RouteInformation(通常包含一个 URI 字符串)解析成你的「配置模型」(configuration),比如一个自定义的 MyRoutePath 对象。
  3. RouterDelegate 根据当前的「配置模型」构建并返回一个 Navigator,通常是一个带有 pages: List<Page> 的声明式导航栈。你在这里决定要哪些页面、以何种顺序展示。
  4. BackButtonDispatcher (可选)用于处理 Android/iOS 的返回按钮或 Web 上的前进后退。
  5. Page & Route Navigator 2.0 推荐使用 Page 对象(如 MaterialPageCupertinoPage)来描述页面,而不是直接推 Route

示例#

import 'package:flutter/material.dart';

// 1. 定义路由配置模型
class MyRoutePath {
  final String? location;
  MyRoutePath.home() : location = '/';
  MyRoutePath.details(this.location);
}

// 2. 解析 URL → 配置
class MyRouteParser extends RouteInformationParser<MyRoutePath> {
  @override
  Future<MyRoutePath> parseRouteInformation(
      RouteInformation routeInformation) async {
    final uri = Uri.parse(routeInformation.location ?? '/');
    if (uri.pathSegments.isEmpty) {
      return MyRoutePath.home();
    } else {
      return MyRoutePath.details('/' + uri.pathSegments.join('/'));
    }
  }

  @override
  RouteInformation restoreRouteInformation(MyRoutePath configuration) {
    return RouteInformation(location: configuration.location);
  }
}

// 3. 根据配置构建 Navigator
class MyRouterDelegate extends RouterDelegate<MyRoutePath>
    with ChangeNotifier, PopNavigatorRouterDelegateMixin<MyRoutePath> {
  final GlobalKey<NavigatorState> navigatorKey;

  String? _selectedLocation;

  MyRouterDelegate() : navigatorKey = GlobalKey<NavigatorState>();

  MyRoutePath get currentConfiguration {
    if (_selectedLocation == null) {
      return MyRoutePath.home();
    }
    return MyRoutePath.details(_selectedLocation);
  }

  @override
  Widget build(BuildContext context) {
    return Navigator(
      key: navigatorKey,
      pages: [
        // 始终存在的首页
        MaterialPage(key: ValueKey('HomePage'), child: HomePage(onTap: _handleTap)),
        // 如果有选中,就在栈顶加一个详情页
        if (_selectedLocation != null)
          MaterialPage(
            key: ValueKey('DetailsPage'),
            child: DetailsPage(location: _selectedLocation!),
          ),
      ],
      onPopPage: (route, result) {
        if (!route.didPop(result)) return false;
        // 处理返回:清空选中,刷新
        _selectedLocation = null;
        notifyListeners();
        return true;
      },
    );
  }

  void _handleTap(String location) {
    _selectedLocation = location;
    notifyListeners();
  }

  @override
  Future<void> setNewRoutePath(MyRoutePath configuration) async {
    if (configuration.location == '/') {
      _selectedLocation = null;
    } else {
      _selectedLocation = configuration.location;
    }
  }
}

// 4. 定义首页和详情页
class HomePage extends StatelessWidget {
  final void Function(String) onTap;
  HomePage({required this.onTap});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('首页')),
      body: ListView(
        children: ['foo', 'bar', 'baz']
            .map((e) => ListTile(title: Text(e), onTap: () => onTap(e)))
            .toList(),
      ),
    );
  }
}

class DetailsPage extends StatelessWidget {
  final String location;
  DetailsPage({required this.location});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('详情:$location')),
      body: Center(child: Text('当前路由:$location')),
    );
  }
}

// 5. 在 MaterialApp 中使用 Router
void main() {
  runApp(MaterialApp.router(
    routeInformationParser: MyRouteParser(),
    routerDelegate: MyRouterDelegate(),
  ));
}

使用#

  1. 定义“路由状态”模型,表示你的页面或子页面状态(如 MyRoutePath)。
  2. 实现 RouteInformationParser,把 URL ↔ 状态模型 相互转换。
  3. 实现 RouterDelegate,在 build() 中返回一个声明式的 Navigator(pages: […]),并在用户交互或路由变化时通过 notifyListeners() 更新。
  4. 在 MaterialApp.router(或 CupertinoApp.router)中指定这两个组件。

这样就完成了一个最基础的 Navigator 2.0 架构,你可以在此基础上扩展子路由、嵌套路由、命名路由、守卫、404 页面、Web 深度链接等功能。

Flutter Navigator v2
https://blog.lpkt.cn/posts/flutter-navigator-v2/
作者
lollipopkit
发布于
2025-05-07
许可协议
CC BY-NC-SA 4.0