Flutter全局路由封装及路由栈维护

1. 路由选择

Flutter路由跳转方式有如下两种:

  1. 基本路由

    Navigator.of(context).push(
        MaterialPageRoute(
           builder: (context)=>Detail()
        )
    );
    
  2. 命名式路由

    Navigator.pushNamed(context, "Detail")
    

我选择了后者,主要原因是符合我之前做RN时的路由习惯,并无其他深层的原因。另外在此不再赘述两种路由的具体使用,后续代码默认大家都熟悉这一块。

2. 需要解决的问题

  1. 不管使用哪种路由方式都需要获取当前路由上下文context,但并非所有路由跳转都可以直接获取到当前路由上下文

    ROUTE文件 1️⃣ 2️⃣ 组合技解决该问题

  2. 在有Tab路由情况下,如何返回指定Tab页

    曾经天真的认为会有现成的API,但一顿尝试以后并没有找到,无奈只能借用通知机制处理,详情见ROUTE文件3️⃣

  3. flutter没有提供获取路由栈的方法,因此只能自己维护(见ROUTE文件4️⃣),但又面临如下两个问题:

    • 如何在触发iOS侧滑或Android物理返回键时将当前路由出栈
    • flutter中Modal是通过路由的方式弹出的,在维护路由栈时又是如何排除Modal的出栈与入栈呢

    如果你看了ROUTE中每个跳转维护路由栈的逻辑,你会发现一个奇怪的现象:所有的pop方法里我都没有对路由栈做出栈操作。这是因为我在MaterialApp 增加了一个navigatorObservers监听,即GlobalNavigatorObserver(源码在最后)。路由中的任何pop操作都会触发该监听中的didPop方法,包括iOS侧滑Android物理返回键Modal的pop。因此pop的路由栈维护就交给了GlobalNavigatorObserver。

2. 源码分析

ROUTE.dart



// 1️⃣ 将该值赋给MaterialApp的navigatorKey属性
GlobalKey<NavigatorState> NavigatorKey = GlobalKey();
// 2️⃣ 获取当前路由对象,可以通过Navigtaion.context获取当前路由上下文
var Navigation = NavigatorKey.currentState;

class ROUTE {

  // 4️⃣ 手动维护的路由栈,每次路由操作都会对该数组进行出栈入栈操作
  static List<String> history = [];

  static Future push(name, [params]) {
    history.add(name);
    print('当前路由栈 $history');
    return Navigation.pushNamed(name, arguments: params);
  }

  static void pushAnomymous(name, [params]) {
    // 是否登录的判断
    if (user?.uid == null) {
      push("LoginPage",params);
    } else {
      push(name, params);
    }
  }

  // Modal的pop,再次统一管理,另外也必须使用Navigation下的context,否则会影响路由栈
  static modalPop() {
    Navigator.of(Navigation.context).pop();
  }

  // value是回调的值
  static void pop([value]) {
    Navigation.pop(value);
  }

  // pop到指定页面
  static void popTo(name) {
    Navigation.popUntil(ModalRoute.withName(name));
  }

  static void goToTab(tab) async {
    popTo('/');
    history = [name];
    // 3️⃣ 借用通知,告知Tab页要切换的tab项。EventBus是自己网上找的通知封装,如果需要可以评论或私信
    EventBus().emit('PopTab', {'tab': tab});
  }

  // 当前路由栈是否可pop
  static bool canPop() {
    return Navigation.canPop();
  }

  // 会先调用canPop,若返回false则无效果
  static void maybePop() {
    Navigation.maybePop();
  }

  static Future replace(name, [params]) async {
    var arg = Map();
    arg.addAll(params ?? {});
    arg['replace'] = true;
    if (history.isNotEmpty) {
      history.removeLast();
    }
    history.add(name);

    await Navigation.pushReplacementNamed(name, arguments: arg);
  }

  // 先执行pop再执行push
  static void popAndPush(name) {
    if (history.isNotEmpty) {
      history.removeLast();
    }
    history.add(name);
    Navigation.popAndPushNamed(name);
  }

  // push并重置路由栈,可以通过第二个回调来保留某些路由栈
  static Future pushReset(name) {
    history = [name];
    return Navigation.pushNamedAndRemoveUntil(name, (route) => false);
  }
}

GlobalNavigatorObserver.dart

import 'package:app/functions/route/route.dart';
import 'package:flutter/material.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';

class GlobalNavigatorObserver extends NavigatorObserver {
  
  @override
  void didPop(Route route, Route previousRoute) {
    super.didPop(route, previousRoute);
    if (route is ModalBottomSheetRoute || route is DialogRoute) return;
    ROUTE.restoreGlobarBar();
    ROUTE.history.removeLast();
  }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值