在flutter中 route是一個繞不開,必須面對,且很常用東西
Route就是路由,顧名思義,負責你頁面間的跳轉
不想看程式碼和思路分析的直接copy了拿去用就行 沒有啥外部依賴,只需要注意_rootRoute 後面的字串需要和initialRoute 對應即可
路由又分靜態和動態路由
靜態就是不需要傳引數的,這樣的路由可以直接定義在MaterialApp/WidgetsApp 裡這樣可以通過Navigator.pushNamed
呼叫
動態的就是傳入一個PageRoute
, 通常是一個MaterialPageRoute
或者CupertinoPageRoute
,或者你如果有自定義的有可以使用
這裡我使用一個我的工具類來實現跳轉,因為大部分情況下,工程中的路由都是動態的,也就是需要傳引數的,所以工具類中只包含了使用Widget相關的方案
import 'dart:async';
import 'package:flutter/material.dart';
class RouteHelper {
static Future<
T>
pushWidget<
T>
( BuildContext context, Widget widget, {
bool replaceRoot = false, bool replaceCurrent = false,
}) {
return pushRoute( context, MaterialPageRoute(builder: (ctx) =>
widget), replaceRoot: replaceRoot, replaceCurrent: replaceCurrent, );
} static Future<
T>
pushRoute<
T>
( BuildContext context, PageRoute<
T>
route, {
bool replaceRoot = false, bool replaceCurrent = false,
}) {
assert(!(replaceRoot == true &
&
replaceCurrent == true));
if (replaceRoot == true) {
return Navigator.pushAndRemoveUntil( context, route, _rootRoute, );
} if (replaceCurrent == true) {
return Navigator.pushReplacement(context, route);
} return Navigator.push(context, route);
}
}var _rootRoute = ModalRoute.withName("home");
複製程式碼
解析一下這個類,有兩個方法,一個是接受PageRoute,一個是接收Widget
接收Widget的是講Widget包裝為MaterialPageRoute,然後傳給另一個方法
另一個方法中包含3種情況,一種是替換根節點,一種是替換當前頁面(關閉當前,且開啟新頁面),還有一種就是平常的push(即 不關閉當前,直接開啟新的)
根據傳參不同而有所不同
有一個_rootRoute
變數,這個變數的目的是用於替換根節點,'home'
是我定義在MaterialApp
裡的initialRoute
,這樣一一對應才能確保替換根節點
當然這個類也可以繼續擴充套件,比如將routes定義在內,然後傳route name 引數,接著通過routes來提取出named對應的Widget/Route 接著傳入pushRoute
方法進行跳轉即可
這個簡便的Helper還有另一個好處,就是可以方便後續批量替換Route實現,比如有一天你想自定義一個PageRoute,不使用MaterialRoute ,那麼你只需要替換如下如所示的部分即可
當然還可以有別的擴充套件方法來支援named
比如檢視Navigator
的原始碼發現pushNamed
,就是通過widget.onGenerateRoute
方法獲取到route
的,我這裡直接在helper中寫就好了
Helper 寫完了,我們看看使用的方法使用起來也很簡單
比如強登陸應用
void _login() {
RouteHelper.pushWidget(context, HomeRootPage(), replaceRoot: true);
}複製程式碼
這裡登入成功後,我直接替換了root節點,然後根路由就變成了主頁面
void _forgetPwd() {
RouteHelper.pushWidget(context, ForgetPwdPage());
} void _register() {
RouteHelper.pushWidget(context, RegiseterPage());
}複製程式碼
忘記密碼和註冊都基於登入在做,最終要返回登入,所以這裡用普通的呼叫方法
_register() {
RouteHelper.pushWidget( context, RegisterSuccessPage(), replaceCurrent: true, );
}複製程式碼
註冊成功後我這裡有一個單獨的註冊成功頁,寫了一些註冊後的注意事項,而返回又應該直接返回到登入頁面,所以這裡我需要替換掉當前的頁面,只用replaceCurrent 即可
當然方法接受返回值也是允許的
_orderDetail(String item) async {
//todo 檢視訂單詳情 var result = await RouteHelper.pushWidget<
bool>
(context, OrderDetailPage(id: item));
if (result == true) {
_refresh();
}
}複製程式碼
這裡如果在詳情頁買了東西/加到購物車,回到主頁面,是要重新整理頁面的,所以我們接收返回值,然後判斷
小tips:這裡之所以用result == true 而不是 if(result) 是因為dart中 bool
是有3個值的 true false nullif(result==true)
可以將result 為 null的情況規避掉,提升程式碼健壯性,這個不得不說是dart 完全物件導向造成的副作用