557 lines
13 KiB
Markdown
557 lines
13 KiB
Markdown
- [路由管理](#路由管理)
|
||
- [如何使用](#如何使用)
|
||
- [普通路由导航](#普通路由导航)
|
||
- [别名路由导航](#别名路由导航)
|
||
- [发送数据到别名路由](#发送数据到别名路由)
|
||
- [动态网页链接](#动态网页链接)
|
||
- [中间件](#中间件)
|
||
- [免context导航](#免context导航)
|
||
- [SnackBars](#SnackBars)
|
||
- [Dialogs](#dialogs)
|
||
- [BottomSheets](#bottomSheets)
|
||
- [嵌套导航](#嵌套导航)
|
||
|
||
# 路由管理
|
||
|
||
这是关于Getx在路由管理方面的完整解释。
|
||
|
||
## 如何使用
|
||
|
||
将此添加到你的pubspec.yaml文件中。
|
||
|
||
```yaml
|
||
dependencies:
|
||
get:
|
||
```
|
||
|
||
如果你要在没有context的情况下使用路由/SnackBars/Dialogs/BottomSheets,或者使用高级的Get API,你只需要在你的MaterialApp前面加上 "Get",就可以把它变成GetMaterialApp,享受吧!
|
||
|
||
```dart
|
||
GetMaterialApp( // Before: MaterialApp(
|
||
home: MyHome(),
|
||
)
|
||
```
|
||
|
||
## 普通路由导航
|
||
|
||
导航到新的页面。
|
||
|
||
```dart
|
||
Get.to(NextScreen());
|
||
```
|
||
|
||
关闭SnackBars、Dialogs、BottomSheets或任何你通常会用Navigator.pop(context)关闭的东西。
|
||
|
||
```dart
|
||
Get.back();
|
||
```
|
||
|
||
进入下一个页面,但没有返回上一个页面的选项(用于SplashScreens,登录页面等)。
|
||
|
||
```dart
|
||
Get.off(NextScreen());
|
||
```
|
||
|
||
进入下一个界面并取消之前的所有路由(在购物车、投票和测试中很有用)。
|
||
|
||
```dart
|
||
Get.offAll(NextScreen());
|
||
```
|
||
|
||
要导航到下一条路由,并在返回后立即接收或更新数据。
|
||
|
||
```dart
|
||
var data = await Get.to(Payment());
|
||
```
|
||
|
||
在另一个页面上,发送前一个路由的数据。
|
||
|
||
```dart
|
||
Get.back(result: 'success');
|
||
```
|
||
|
||
并使用它,例:
|
||
|
||
```dart
|
||
if(data == 'success') madeAnything();
|
||
```
|
||
|
||
你不想学习我们的语法吗?
|
||
只要把 Navigator(大写)改成 navigator(小写),你就可以拥有标准导航的所有功能,而不需要使用context,例如:
|
||
|
||
```dart
|
||
|
||
// 默认的Flutter导航
|
||
Navigator.of(context).push(
|
||
context,
|
||
MaterialPageRoute(
|
||
builder: (BuildContext context) {
|
||
return HomePage();
|
||
},
|
||
),
|
||
);
|
||
|
||
// 使用Flutter语法获得,而不需要context。
|
||
navigator.push(
|
||
MaterialPageRoute(
|
||
builder: (_) {
|
||
return HomePage();
|
||
},
|
||
),
|
||
);
|
||
|
||
// get语法 (这要好得多)
|
||
Get.to(HomePage());
|
||
|
||
|
||
```
|
||
|
||
## 别名路由导航
|
||
|
||
- 如果你喜欢用别名路由导航,Get也支持。
|
||
|
||
导航到下一个页面
|
||
|
||
```dart
|
||
Get.toNamed("/NextScreen");
|
||
```
|
||
|
||
浏览并删除前一个页面。
|
||
|
||
```dart
|
||
Get.offNamed("/NextScreen");
|
||
```
|
||
|
||
浏览并删除所有以前的页面。
|
||
|
||
```dart
|
||
Get.offAllNamed("/NextScreen");
|
||
```
|
||
|
||
要定义路由,使用GetMaterialApp。
|
||
|
||
```dart
|
||
void main() {
|
||
runApp(
|
||
GetMaterialApp(
|
||
initialRoute: '/',
|
||
getPages: [
|
||
GetPage(name: '/', page: () => MyHomePage()),
|
||
GetPage(name: '/second', page: () => Second()),
|
||
GetPage(
|
||
name: '/third',
|
||
page: () => Third(),
|
||
transition: Transition.zoom
|
||
),
|
||
],
|
||
)
|
||
);
|
||
}
|
||
```
|
||
|
||
要处理到未定义路线的导航(404错误),可以在GetMaterialApp中定义unknownRoute页面。
|
||
|
||
```dart
|
||
void main() {
|
||
runApp(
|
||
GetMaterialApp(
|
||
unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),
|
||
initialRoute: '/',
|
||
getPages: [
|
||
GetPage(name: '/', page: () => MyHomePage()),
|
||
GetPage(name: '/second', page: () => Second()),
|
||
],
|
||
)
|
||
);
|
||
}
|
||
```
|
||
|
||
### 发送数据到别名路由
|
||
|
||
只要发送你想要的参数即可。Get在这里接受任何东西,无论是一个字符串,一个Map,一个List,甚至一个类的实例。
|
||
|
||
```dart
|
||
Get.toNamed("/NextScreen", arguments: 'Get is the best');
|
||
```
|
||
|
||
在你的类或控制器上:
|
||
|
||
```dart
|
||
print(Get.arguments);
|
||
//print out: Get is the best
|
||
```
|
||
|
||
### 动态网页链接
|
||
|
||
Get提供高级动态URL,就像在Web上一样。Web开发者可能已经在Flutter上想要这个功能了,Get也解决了这个问题。
|
||
|
||
```dart
|
||
Get.offAllNamed("/NextScreen?device=phone&id=354&name=Enzo");
|
||
```
|
||
|
||
在你的controller/bloc/stateful/stateless类上:
|
||
|
||
```dart
|
||
print(Get.parameters['id']);
|
||
// out: 354
|
||
print(Get.parameters['name']);
|
||
// out: Enzo
|
||
```
|
||
|
||
你也可以用Get轻松接收NamedParameters。
|
||
|
||
```dart
|
||
void main() {
|
||
runApp(
|
||
GetMaterialApp(
|
||
initialRoute: '/',
|
||
getPages: [
|
||
GetPage(
|
||
name: '/',
|
||
page: () => MyHomePage(),
|
||
),
|
||
GetPage(
|
||
name: '/profile/',
|
||
page: () => MyProfile(),
|
||
),
|
||
//你可以为有参数的路由定义一个不同的页面,也可以为没有参数的路由定义一个不同的页面,但是你必须在不接收参数的路由上使用斜杠"/",就像上面说的那样。
|
||
GetPage(
|
||
name: '/profile/:user',
|
||
page: () => UserProfile(),
|
||
),
|
||
GetPage(
|
||
name: '/third',
|
||
page: () => Third(),
|
||
transition: Transition.cupertino
|
||
),
|
||
],
|
||
)
|
||
);
|
||
}
|
||
```
|
||
|
||
发送别名路由数据
|
||
|
||
```dart
|
||
Get.toNamed("/second/34954");
|
||
```
|
||
|
||
在第二个页面上,通过参数获取数据
|
||
|
||
```dart
|
||
print(Get.parameters['user']);
|
||
// out: 34954
|
||
```
|
||
|
||
或像这样发送多个参数
|
||
|
||
```dart
|
||
Get.toNamed("/profile/34954?flag=true");
|
||
```
|
||
|
||
在第二个屏幕上,通常按参数获取数据
|
||
|
||
```dart
|
||
print(Get.parameters['user']);
|
||
print(Get.parameters['flag']);
|
||
// out: 34954 true
|
||
```
|
||
|
||
|
||
现在,你需要做的就是使用Get.toNamed()来导航你的别名路由,不需要任何context(你可以直接从你的BLoC或Controller类中调用你的路由),当你的应用程序被编译到web时,你的路由将出现在URL中。
|
||
|
||
### 中间件
|
||
|
||
如果你想通过监听Get事件来触发动作,你可以使用routingCallback来实现。
|
||
|
||
```dart
|
||
GetMaterialApp(
|
||
routingCallback: (routing) {
|
||
if(routing.current == '/second'){
|
||
openAds();
|
||
}
|
||
}
|
||
)
|
||
```
|
||
|
||
如果你没有使用GetMaterialApp,你可以使用手动API来附加Middleware观察器。
|
||
|
||
```dart
|
||
void main() {
|
||
runApp(
|
||
MaterialApp(
|
||
onGenerateRoute: Router.generateRoute,
|
||
initialRoute: "/",
|
||
navigatorKey: Get.key,
|
||
navigatorObservers: [
|
||
GetObserver(MiddleWare.observer), // HERE !!!
|
||
],
|
||
),
|
||
);
|
||
}
|
||
```
|
||
|
||
创建一个MiddleWare类
|
||
|
||
```dart
|
||
class MiddleWare {
|
||
static observer(Routing routing) {
|
||
///你除了可以监听路由外,还可以监听每个页面上的SnackBars、Dialogs和Bottomsheets。
|
||
if (routing.current == '/second' && !routing.isSnackbar) {
|
||
Get.snackbar("Hi", "You are on second route");
|
||
} else if (routing.current =='/third'){
|
||
print('last route called');
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
现在,在你的代码上使用Get:
|
||
|
||
```dart
|
||
class First extends StatelessWidget {
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar: AppBar(
|
||
leading: IconButton(
|
||
icon: Icon(Icons.add),
|
||
onPressed: () {
|
||
Get.snackbar("hi", "i am a modern snackbar");
|
||
},
|
||
),
|
||
title: Text('First Route'),
|
||
),
|
||
body: Center(
|
||
child: ElevatedButton(
|
||
child: Text('Open route'),
|
||
onPressed: () {
|
||
Get.toNamed("/second");
|
||
},
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
class Second extends StatelessWidget {
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar: AppBar(
|
||
leading: IconButton(
|
||
icon: Icon(Icons.add),
|
||
onPressed: () {
|
||
Get.snackbar("hi", "i am a modern snackbar");
|
||
},
|
||
),
|
||
title: Text('second Route'),
|
||
),
|
||
body: Center(
|
||
child: ElevatedButton(
|
||
child: Text('Open route'),
|
||
onPressed: () {
|
||
Get.toNamed("/third");
|
||
},
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
class Third extends StatelessWidget {
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar: AppBar(
|
||
title: Text("Third Route"),
|
||
),
|
||
body: Center(
|
||
child: ElevatedButton(
|
||
onPressed: () {
|
||
Get.back();
|
||
},
|
||
child: Text('Go back!'),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|
||
```
|
||
|
||
## 免context导航
|
||
|
||
### SnackBars
|
||
|
||
用Flutter创建一个简单的SnackBar,你必须获得Scaffold的context,或者你必须使用一个GlobalKey附加到你的Scaffold上。
|
||
|
||
```dart
|
||
final snackBar = SnackBar(
|
||
content: Text('Hi!'),
|
||
action: SnackBarAction(
|
||
label: 'I am a old and ugly snackbar :(',
|
||
onPressed: (){}
|
||
),
|
||
);
|
||
// 在小组件树中找到脚手架并使用它显示一个SnackBars。
|
||
Scaffold.of(context).showSnackBar(snackBar);
|
||
```
|
||
|
||
用Get:
|
||
|
||
```dart
|
||
Get.snackbar('Hi', 'i am a modern snackbar');
|
||
```
|
||
|
||
有了Get,你所要做的就是在你代码的任何地方调用你的Get.snackbar,或者按照你的意愿定制它。
|
||
|
||
```dart
|
||
Get.snackbar(
|
||
"Hey i'm a Get SnackBar!", // title
|
||
"It's unbelievable! I'm using SnackBar without context, without boilerplate, without Scaffold, it is something truly amazing!", // message
|
||
icon: Icon(Icons.alarm),
|
||
shouldIconPulse: true,
|
||
onTap:(){},
|
||
barBlur: 20,
|
||
isDismissible: true,
|
||
duration: Duration(seconds: 3),
|
||
);
|
||
|
||
|
||
////////// ALL FEATURES //////////
|
||
// Color colorText,
|
||
// Duration duration,
|
||
// SnackPosition snackPosition,
|
||
// Widget titleText,
|
||
// Widget messageText,
|
||
// bool instantInit,
|
||
// Widget icon,
|
||
// bool shouldIconPulse,
|
||
// double maxWidth,
|
||
// EdgeInsets margin,
|
||
// EdgeInsets padding,
|
||
// double borderRadius,
|
||
// Color borderColor,
|
||
// double borderWidth,
|
||
// Color backgroundColor,
|
||
// Color leftBarIndicatorColor,
|
||
// List<BoxShadow> boxShadows,
|
||
// Gradient backgroundGradient,
|
||
// TextButton mainButton,
|
||
// OnTap onTap,
|
||
// bool isDismissible,
|
||
// bool showProgressIndicator,
|
||
// AnimationController progressIndicatorController,
|
||
// Color progressIndicatorBackgroundColor,
|
||
// Animation<Color> progressIndicatorValueColor,
|
||
// SnackStyle snackStyle,
|
||
// Curve forwardAnimationCurve,
|
||
// Curve reverseAnimationCurve,
|
||
// Duration animationDuration,
|
||
// double barBlur,
|
||
// double overlayBlur,
|
||
// Color overlayColor,
|
||
// Form userInputForm
|
||
///////////////////////////////////
|
||
```
|
||
|
||
如果您喜欢传统的SnackBars,或者想从头开始定制,包括只添加一行(Get.snackbar使用了一个强制性的标题和信息),您可以使用
|
||
`Get.rawSnackbar();`它提供了建立Get.snackbar的RAW API。
|
||
|
||
### Dialogs
|
||
|
||
打开Dialogs:
|
||
|
||
```dart
|
||
Get.dialog(YourDialogWidget());
|
||
```
|
||
|
||
打开默认Dialogs:
|
||
|
||
```dart
|
||
Get.defaultDialog(
|
||
onConfirm: () => print("Ok"),
|
||
middleText: "Dialog made in 3 lines of code"
|
||
);
|
||
```
|
||
|
||
你也可以用Get.generalDialog代替showGeneralDialog。
|
||
|
||
对于所有其他的FlutterDialogs小部件,包括cupertinos,你可以使用Get.overlayContext来代替context,并在你的代码中任何地方打开它。
|
||
对于不使用Overlay的小组件,你可以使用Get.context。
|
||
这两个context在99%的情况下都可以代替你的UIcontext,除了在没有导航context的情况下使用 inheritedWidget的情况。
|
||
|
||
### BottomSheets
|
||
|
||
Get.bottomSheet类似于showModalBottomSheet,但不需要context:
|
||
|
||
```dart
|
||
Get.bottomSheet(
|
||
Container(
|
||
child: Wrap(
|
||
children: <Widget>[
|
||
ListTile(
|
||
leading: Icon(Icons.music_note),
|
||
title: Text('Music'),
|
||
onTap: () {}
|
||
),
|
||
ListTile(
|
||
leading: Icon(Icons.videocam),
|
||
title: Text('Video'),
|
||
onTap: () {},
|
||
),
|
||
],
|
||
),
|
||
)
|
||
);
|
||
```
|
||
|
||
## 嵌套导航
|
||
|
||
Get让Flutter的嵌套导航更加简单。
|
||
你不需要context,而是通过Id找到你的导航栈。
|
||
|
||
- 注意:创建平行导航堆栈可能是危险的。理想的情况是不要使用NestedNavigators,或者尽量少用。如果你的项目需要它,请继续,但请记住,在内存中保持多个导航堆栈可能不是一个好主意(消耗RAM)。
|
||
|
||
看看它有多简单:
|
||
|
||
```dart
|
||
Navigator(
|
||
key: Get.nestedKey(1), // create a key by index
|
||
initialRoute: '/',
|
||
onGenerateRoute: (settings) {
|
||
if (settings.name == '/') {
|
||
return GetPageRoute(
|
||
page: () => Scaffold(
|
||
appBar: AppBar(
|
||
title: Text("Main"),
|
||
),
|
||
body: Center(
|
||
child: TextButton(
|
||
color: Colors.blue,
|
||
onPressed: () {
|
||
Get.toNamed('/second', id:1); // navigate by your nested route by index
|
||
},
|
||
child: Text("Go to second"),
|
||
),
|
||
),
|
||
),
|
||
);
|
||
} else if (settings.name == '/second') {
|
||
return GetPageRoute(
|
||
page: () => Center(
|
||
child: Scaffold(
|
||
appBar: AppBar(
|
||
title: Text("Main"),
|
||
),
|
||
body: Center(
|
||
child: Text("second")
|
||
),
|
||
),
|
||
),
|
||
);
|
||
}
|
||
}
|
||
),
|
||
```
|