本教程前半部分屬于入門搀矫,后半部分屬于進階
1.routes 和navigator 的關系 ?
大部分應用程序都包含多個頁面,并希望用戶能從當前屏幕平滑過渡到另一個屏幕启泣。移動應用程序通常通過被稱為“屏幕”或“頁面”的全屏元素來顯示內容Flutter 中,這些元素被稱為路由(Route)束析,它們由導航器(Navigator)控件管理县习。導航器管理著路由對象的堆棧并提供管理堆棧的方法沟启,如
Navigator.push
和Navigator.pop
三娩,通過路由對象的進出棧來使用戶從一個頁面跳轉到另一個頁面鸿脓。
2. 怎么使用 抑钟?
(1)push方法
設置一個構造函數 (第二個page的初始方法)
final String title;
Page({this.title});
跳轉傳值
Navigator.push(context,
MaterialPageRoute(builder: (context) => Page(title: "題目")));
返回
Navigator.pop(context);
(2) pushName方法
在初始化APP的地方MaterialApp,設置一個路由列表
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp( // 這個是標記
home: MainPage(),
debugShowCheckedModeBanner: false,
routes: { // 就是它
'/page':(context) => Page()
'/home':(context) => Home()
},
);
}
}
在需要跳轉的時候
Navigator.pushNamed(context, '/page');
這里有一個問題就是使用 Navigator.pushNamed 時無法直接給新頁面?zhèn)鲄狄翱蓿壳肮俜竭€沒有標準解決方案在塔,我知道的方案是在 onGenerateRoute 回調方法和arguments參數設置。
完整事例
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
//監(jiān)聽導航routes 數據 PassArguments
onGenerateRoute: (settings) {
//對比路由名稱
if (settings.name == PassArgumentsScreen.routeName) {
final ScreenArguments args = settings.arguments;
//返回 MaterialPageRoute
return MaterialPageRoute(
builder: (context) {
return PassArgumentsScreen(
title: args.title,
message: args.message,
);
},
);
}
},
title: 'Navigation with Arguments',
home: HomeScreen(),
);
}
}
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home Screen'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
//設置一個button
RaisedButton(
child: Text("Navigate to screen that extracts arguments"),
onPressed: () {
// 設置傳值參數 arguments /settings
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ExtractArgumentsScreen(),
settings: RouteSettings(
arguments: ScreenArguments(
'Extract Arguments Screen',
'This message is extracted in the build method.',
),
),
),
);
},
),
RaisedButton(
child: Text("Navigate to a named that accepts arguments"),
onPressed: () {
Navigator.pushNamed(
context,
PassArgumentsScreen.routeName,
arguments: ScreenArguments(
'Accept Arguments Screen',
'This message is extracted in the onGenerateRoute function.',
),
);
},
),
],
),
),
);
}
}
// push界面
class ExtractArgumentsScreen extends StatelessWidget {
static const routeName = '/extractArguments';
@override
Widget build(BuildContext context) {
final ScreenArguments args = ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar: AppBar(
title: Text(args.title),
),
body: Center(
child: Text(args.message),
),
);
}
}
//接受界面
class PassArgumentsScreen extends StatelessWidget {
static const routeName = '/passArguments';
final String title;
final String message;
// MaterialApp widget.
const PassArgumentsScreen({
Key key,
@required this.title,
@required this.message,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(title),
),
body: Center(
child: Text(message),
),
);
}
}
// 設置任意參數
class ScreenArguments {
final String title;
final String message;
ScreenArguments(this.title, this.message);
}
看懂了上面的原理當然可以簡化了虐拓。
定義要接受參數的界面的時候
// 定義接受的構造函數
final arguments心俗;
Page({this.arguments};
在上一界面?zhèn)髦档臅r候
Navigator.pushNamed(context,'/search',argument:{
'id':'1123'; // 參數隨便寫
'name':'sunny'
})
當然路由配置的時候要這樣
final routes = {
'page':(context,{arguments})=>Page(arguments:arguments);
'page':(context,{arguments})=>Page(arguments:arguments);
'page':(context,{arguments})=>Page(arguments:arguments);
'page':(context,{arguments})=>Page(arguments:arguments);
}
final String name = setting.name;
final Function pagContentBuilder = this.routes[name];
當然你也可以吧參數和路由名稱都封裝到一個類中去 。說說思路蓉驹,全局單利路由文件設置好 城榛,設置路由對象 ,對象的個數和名稱提前固定 态兴,可以根據名稱隨時更改需要傳值的參數 狠持。 在界面跳轉前更改參數 ,傳入參數 瞻润,在界面跳轉后接受數據喘垂。
面對逆向的時候還可以加上加密措施和代碼混淆
//Routes.dart
import 'pa/material' import '所有界面'
final routes = {
'page':(context,{arguments})=>Page(arguments:arguments);
'page':(context,{arguments})=>Page(arguments:arguments);
'page':(context,{arguments})=>Page(arguments:arguments);
'page':(context,{arguments})=>Page(arguments:arguments);
}
// 生成路由回調的的固定寫法
var onGenerateroute = (RounteSettings setting){
final String name = setting.name;
final Function pagContentBuilder = routes[name];
if (pagContentBuilder != null){
if(setting.arguments != null){
final Route route = MaterialpageRoute(
buider:(context) =>
PageContentBuilder(context,arguments:setting.arguments);
)
return route;
}else{
final Route route = MaterialpageRoute(
buider:(context) =>
PageContentBuilder(context);
)
return route;
}
}
}
3.路由的命名規(guī)范 ?
樹狀結構命名法
'\' #主頁
'\home' #主頁 下 home界面
'\my' #主頁 下 my界面
'\home\name' #主頁 下 home界面 下name界面
3.initialRoute 的作用 ?
initialRoute
同樣是MaterialApp
的屬性 ,也就是相當于iOS里面的appdelegate部分绍撞,在全局只能設置一次 正勒。 在routes
里面設置的路由都可以通過initialRoute
來設置,也就是第一次啟動app時候傻铣,我們的初始界面是那個章贞。
路由的返回功能
Navigator.of(context).pop();
返回根路由/ 替換路由 在跳轉的時候使用替換路由,在返回的時候會直接返回到根目錄
Navigator.of(context).pushReplacementNamed('/firstPage');
或者直接返回根的代碼/ 沒有的話直接更改界面 非洲。
Navigator.of(context).pushAndRemoveUntil(
// 中間的界面置為空鸭限,直到我們返回的頁面。
newMaterialPageRutes(builder:context)=>new Tab bar(index : 1),
(route)=>route==null;
)
(??????看到這里的都很厲害两踏,給你們點終極福利)??????
fluro的封裝使用
國外都流行用這個現在败京,下面是最權威的封裝
1設置一個全局的router,
形式多樣梦染,單例都可以,此處就放到Application類中了赡麦。
//application.dart
import 'package:fluro/fluro.dart';
class Application {
static Router router;
}
2. 設置router 信息
引入handle文件,具體界面目錄
//routers.dart
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:~/route_handlers.dart';
class Routes {
static String root = '/';
//添加路由命名
static String chatDetail = '/chat';
static void configureRoutes(Router router) {
router.notFoundHandler = new Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
print('Route was not found.');
}
);
router.define(root, handler: rootHandler);
//一條一條往后加處理方式
router.define(chatDetail, handler: chatDetailHandler);
}
}
3. 設置routerHandle 信息
具體每個頁面怎么處理都在這個文件中
//route_handlers.dart
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:flutter_whatsapp/src/home.dart';
// 一條一條往后加,此處沒做任何處理
var rootHandler = new Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
return new Home();
}
);
//此處解析了一個參數profileId
var chatDetailHandler = new Handler(
handlerFunc: (BuildContext context, Map<String, List<String>> params) {
int profileId = int.tryParse(params['profileId']?.first) ?? null;
// 此處調用構造方法
return new DetailChatScreen(
id: profileId,
);
}
);
4.使用
在MaterialApp
中初始化
import 'package:fluro/fluro.dart';
import 'package:flutter/material.dart';
import 'package:config/application.dart';
import 'package:config/routes.dart';
import 'package:/src/home.dart';
import 'package:/src/values/colors.dart';
class FlutteredApp extends StatefulWidget {
@override
_FlutteredAppState createState() => _FlutteredAppState();
}
class _FlutteredAppState extends State<FlutteredApp> {
_FlutteredAppState() {
final router = new Router();
Routes.configureRoutes(router);
Application.router = router;
}
/// Default theme.
static final ThemeData _defaultTheme = new ThemeData(
primaryColor: primaryColor,
accentColor: Colors.white,
scaffoldBackgroundColor: scaffoldBgColor,
);
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'setting',
theme: _defaultTheme,
onGenerateRoute: Application.router.generator,
);
}
}
調用
Application.router.navigateTo(
context,
"${Router.chatDetail}?profileId=${id}",
transition: TransitionType.inFromRight,
);
返回
Navigator.of(context).pop();