https://gitee.com/frontend-qin/getx/blob/master/documentation/zh_CN/route_management.md
路由管理
这是关于Getx在路由管理方面的完整解释。
如何使用
将此添加到你的pubspec.yaml文件中。
dependencies:
get:
如果你要在没有context的情况下使用路由/SnackBars/Dialogs/BottomSheets,或者使用高级的Get API,你只需要在你的MaterialApp前面加上 "Get",就可以把它变成GetMaterialApp,享受吧!
GetMaterialApp( // Before: MaterialApp(
home: MyHome(),
)
普通路由导航
导航到新的页面。
Get.to(NextScreen());
关闭SnackBars、Dialogs、BottomSheets或任何你通常会用Navigator.pop(context)关闭的东西。
Get.back();
进入下一个页面,但没有返回上一个页面的选项(用于SplashScreens,登录页面等)。
Get.off(NextScreen());
进入下一个界面并取消之前的所有路由(在购物车、投票和测试中很有用)。
Get.offAll(NextScreen());
要导航到下一条路由,并在返回后立即接收或更新数据。
var data = await Get.to(Payment());
在另一个页面上,发送前一个路由的数据。
Get.back(result: 'success');
并使用它,例:
if(data == 'success') madeAnything();
你不想学习我们的语法吗?
只要把 Navigator(大写)改成 navigator(小写),你就可以拥有标准导航的所有功能,而不需要使用context,例如:
// 默认的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也支持。
导航到下一个页面
Get.toNamed("/NextScreen");
浏览并删除前一个页面。
Get.offNamed("/NextScreen");
浏览并删除所有以前的页面。
Get.offAllNamed("/NextScreen");
要定义路由,使用GetMaterialApp。
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页面。
void main() {
runApp(
GetMaterialApp(
unknownRoute: GetPage(name: '/notfound', page: () => UnknownRoutePage()),
initialRoute: '/',
getPages: [
GetPage(name: '/', page: () => MyHomePage()),
GetPage(name: '/second', page: () => Second()),
],
)
);
}
发送数据到别名路由
只要发送你想要的参数即可。Get在这里接受任何东西,无论是一个字符串,一个Map,一个List,甚至一个类的实例。
Get.toNamed("/NextScreen", arguments: 'Get is the best');
在你的类或控制器上:
print(Get.arguments);
//print out: Get is the best
动态网页链接
Get提供高级动态URL,就像在Web上一样。Web开发者可能已经在Flutter上想要这个功能了,Get也解决了这个问题。
Get.offAllNamed("/NextScreen?device=phone&id=354&name=Enzo");
在你的controller/bloc/stateful/stateless类上:
print(Get.parameters['id']);
// out: 354
print(Get.parameters['name']);
// out: Enzo
你也可以用Get轻松接收NamedParameters。
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
),
],
)
);
}
发送别名路由数据
Get.toNamed("/second/34954");
在第二个页面上,通过参数获取数据
print(Get.parameters['user']);
// out: 34954
或像这样发送多个参数
Get.toNamed("/profile/34954?flag=true");
在第二个屏幕上,通常按参数获取数据
print(Get.parameters['user']);
print(Get.parameters['flag']);
// out: 34954 true
现在,你需要做的就是使用Get.toNamed()来导航你的别名路由,不需要任何context(你可以直接从你的BLoC或Controller类中调用你的路由),当你的应用程序被编译到web时,你的路由将出现在URL中。
中间件
如果你想通过监听Get事件来触发动作,你可以使用routingCallback来实现。
GetMaterialApp(
routingCallback: (routing) {
if(routing.current == '/second'){
openAds();
}
}
)
如果你没有使用GetMaterialApp,你可以使用手动API来附加Middleware观察器。
void main() {
runApp(
MaterialApp(
onGenerateRoute: Router.generateRoute,
initialRoute: "/",
navigatorKey: Get.key,
navigatorObservers: [
GetObserver(MiddleWare.observer), // HERE !!!
],
),
);
}
创建一个MiddleWare类
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:
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上。
final snackBar = SnackBar(
content: Text('Hi!'),
action: SnackBarAction(
label: 'I am a old and ugly snackbar :(',
onPressed: (){}
),
);
// 在小组件树中找到脚手架并使用它显示一个SnackBars。
Scaffold.of(context).showSnackBar(snackBar);
用Get:
Get.snackbar('Hi', 'i am a modern snackbar');
有了Get,你所要做的就是在你代码的任何地方调用你的Get.snackbar,或者按照你的意愿定制它。
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:
Get.dialog(YourDialogWidget());
打开默认Dialogs:
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:
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)。
看看它有多简单:
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")
),
),
),
);
}
}
),