本文對應github地址Flutter11,如果由於github調整導致資源找不到,請訪問github
路由
-
簡介
- iOS中頁面跳轉通過NavigationController,然後pushViewController,Android中可以初始化Intent然後startActivity,Flutter中則路由(Route)方式
- 程式啟動後路由棧第一個(最底部)例項 MaterialApp(home: Screen1())
- 命名路由,對頁面起別名(唯一字串),但一般用有意義字串,如 '/'表示根頁面,'/login'表示登入頁等
-
靜態路由push
- 靜態路由在MeterialApp初始化時配置routes引數,通過起的別名(命名路由)進行跳轉
- 新頁面為配置的固定頁面,且跳轉時引數也是固定的
- 呼叫方法為pushNamed()
// MaterialApp初始化時配置Key-Value void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primaryColor: Colors.red, primarySwatch: Colors.blue, ), home: DDYBottomBar(), showPerformanceOverlay: false, routes: { '/home/qrcode': (BuildContext context) => QRCodeScanner(title: '0',), '/home_qrcode': (BuildContext context) => QRCodeScanner(title: '1',), '+home_qrcode': (BuildContext context) => QRCodeScanner(title: '2',), }, ); } } // 在需要的地方呼叫['/home/qrcode'只是字串名字,並不是真正路徑,這樣仿路徑是為了可讀性] // Navigator.pushNamed(context, '/home/qrcode'); // Navigator.pushNamed(context, '/home_qrcode'); // Navigator.pushNamed(context, '+home_qrcode'); Navigator.of(context).pushNamed('+home_qrcode'); 複製程式碼
-
動態路由push
- 動態路由在需要跳轉時生成要跳轉的頁面物件,傳遞想要的引數,然後呼叫push()函式
// Navigator.push(context, MaterialPageRoute(builder: (context) => QRCodeScanner())); // Navigator.of(context).push(MaterialPageRoute(builder: (_) => QRCodeScanner())); Navigator.of(context).push(MaterialPageRoute(builder: (context) => QRCodeScanner())); 複製程式碼
-
路由pop
- pop()方法中可新增回撥資料
// Navigator.of(context).pop(); // Navigator.pop(context); Navigator.of(context).pop('回撥資料'); 複製程式碼
-
頁面傳值
-
正向傳值直接通過簡單建構函式引數方式即可
-
反向傳值,不同風格其實都一樣,建議第一種
// 風格1 pushQRCodeScannerAndCallbackData1() { Navigator.of(context).push(MaterialPageRoute(builder: (context) => QRCodeScanner())).then((value){ print('1 $value'); }); } // 風格2 pushQRCodeScannerAndCallbackData2() { Future callbackFuture = Navigator.of(context).push(MaterialPageRoute(builder: (_) => QRCodeScanner())); callbackFuture.then((value){ print('2 $value'); }); } // 風格3 pushQRCodeScannerAndCallbackData3() async { // 如果知道型別 String callbackString = await Navigator.of(context).push<String>( MaterialPageRoute(builder: (context){ // 正向傳值直接通過簡單建構函式引數方式即可 return QRCodeScanner(title:'I am 3'); }) ); if (callbackString != null) { print('3 ${callbackString}'); } } // pop()函式引數值即為反向傳回的資料 Navigator.of(context).pop('回撥資料'); 複製程式碼
-
還可以通過閉包作為引數進行傳值
pushQRCodeGenerator() { Navigator.of(context).push( MaterialPageRoute( builder: (context) => QRCodeGenerator((String value) { print('QRCodeGenerator callback $value'); }), ), ); } // 呼叫 IconButton( icon: Icon(Icons.print), onPressed: () { if (widget.callbackFunction != null) { widget.callbackFunction('回撥資料'); } }, ), 複製程式碼
- 定製路由(自定義路由,自定義轉場)
-
繼承路由子類,如:PopupRoute、ModalRoute 等
-
使用 PageRouteBuilder 類通過回撥函式定義路由
- 從下向上彈出,從上向下收回
pushQRCodeScannerWithCustomAnimation() { Navigator.push( context, PageRouteBuilder(pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) { return QRCodeScanner(); }, transitionsBuilder: (context, animation, secondaryAnimation, child) { return transitionAnimation(animation, child); }), ); } static SlideTransition transitionAnimation(Animation<double> animation, Widget child) { return SlideTransition( position: Tween<Offset>( begin: const Offset(0.0, 1.0), end: const Offset(0.0, 0.0), ).animate(animation), child: child, ); } 複製程式碼
- 頁面旋轉淡出的效果
pushQRCodeScannerWithCustomAnimation2() async { // 頁面旋轉淡出的效果 transitionAnimation(Animation<double> animation, Widget child) { return FadeTransition( opacity: animation, child: RotationTransition( turns: Tween<double>(begin: 0.7, end:1.0).animate(animation), child: child, ), ); } Navigator.push( context, PageRouteBuilder( pageBuilder: (context, _, __) => QRCodeScanner(), transitionDuration: const Duration(milliseconds: 1000), transitionsBuilder: (_, animation, __, child) => transitionAnimation(animation, child), ), ).then((value){ Scaffold.of(context).showSnackBar( SnackBar( content: Text(value), duration: const Duration(seconds: 3), ), ); }); } 複製程式碼
- 巢狀路由
-
一個應用程式可以使用多個路由導航器
-
可將一個導航器巢狀在另一個導航器下方使用,例如選項卡式導航,使用者註冊,訂單與結賬頁等
class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( initialRoute: '/', routes: { '/': (BuildContext context) => HomePage(), '/signup': (BuildContext context) => SignUpPage(), }, ); } } class SignUpPage extends StatelessWidget { @override Widget build(BuildContext context) { return Navigator( initialRoute: 'signup/personal_info', onGenerateRoute: (RouteSettings settings) { WidgetBuilder builder; switch (settings.name) { case 'signup/personal_info': // 個人資訊完畢後到 'signup/choose_credentials'. builder = (BuildContext _) => CollectPersonalInfoPage(); break; case 'signup/choose_credentials': // 選完credentials 呼叫 'onSignupComplete()'. builder = (BuildContext _) => ChooseCredentialsPage( onSignupComplete: () { // 回到路由根頁面 '/' (HomePage) Navigator.of(context).pop(); }, ); break; default: throw Exception('Invalid route: ${settings.name}'); } return MaterialPageRoute(builder: builder, settings: settings); }, ); } } 複製程式碼
Navigator
- 繼承自StatefulWidget,路由堆疊的管理者
- 靜態方法詳解
- pushNamed
- pushReplacementNamed
- popAndPushNamed
- pushNamedAndRemoveUntil
- push
- pushReplacement
- pushAndRemoveUntil
- replace
- replaceRouteBelow
- canPop
- maybePop
- popUntil
- removeRoute
- removeRouteBelow
push和pushName
pushName結合配置routes,利用命名路由形式將指定頁面例項(帶固定引數)入棧,而push則是在需要跳轉時生成要跳轉的頁面物件,傳遞想要的引數,兩者執行效果沒差別。
pushReplacement和pushReplacementNamed
兩者都是取代棧頂元素,執行效果沒差別。
popAndPushNamed
顧名思義,先pop然後push
pushAndRemoveUntil 和 pushNamedAndRemoveUntil
兩者都是入棧新頁面刪除除該頁面例項外其他棧內例項,將該例項作為新棧底,執行效果沒差別。可用在註冊登入頁登入後跳轉,防止能返回註冊登入頁
canPop
判斷是否可以pop,如果可以返回true,否則返回false
maybePop
表示在該頁面嘗試pop,如果可以則pop到前一頁,否則仍停在該頁面,丟棄該次pop
popUntil
pop回棧內(該頁面例項以下)指定頁面例項,如 Navigator.popUntil(context, ModalRoute.withName('/home'));
,回到配置名為home的頁面。
其他知識點
-
去除返回按鈕 AppBar中
automaticalImplyLeading: false 複製程式碼
-
Popup routes (彈出路由)
路由不一定要遮擋整個螢幕。 PopupRoutes 使用 ModalRoute.barrierColor 覆蓋螢幕,ModalRoute.barrierColor 只能部分不透明以允許當前螢幕顯示。 彈出路由是“模態”的,因為它們阻止了對下面其他元件的輸入。
有一些方法可以建立和顯示這類彈出路由。 例如:showDialog,showMenu 和 showModalBottomSheet。 如上所述,這些函式返回其推送路由的 Future(非同步資料,參考下面的資料部分)。 執行可以等待返回的值在彈出路由時執行操作。
還有一些元件可以建立彈出路由,如 PopupMenuButton 和 DropdownButton。 這些元件建立 PopupRoute 的內部子類,並使用 Navigator 的push 和 pop 方法來顯示和關閉它們。
參考
上一頁 Flutter10 Icon、Color、Tabbar、BottomNavigationBar
下一頁 Flutter12 IndexedStack、Table、Flow、Warp