Flutter基础(一)页面跳转
一、介绍
在安卓里,界面(Activity)的跳转是通过startActivity来完成。而在Flutter里,把界面称作为一个个Route,他们的跳转是通过一个叫做路由管理(Navigator)的工具,负责页面之前的跳转,包括参数的传递接受和返回。Navigator的方法总的来说就两个,push(进栈),pop(出栈),跟Activity一样也会生成一个存放页面的栈。
二、页面跳转
首先,我们创建一个新的页面,如下
class TwoPageRoute extends StatelessWidget { const TwoPageRoute({Key? key,}) : super(key: key); @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("第二个页面"), ), ); }}
2.1 普通跳转
可以看到,在界面添加了跳转到TwoPageRoute页面的按钮。
TextButton( child: const Text("通过实例跳转"), onPressed: () { Navigator.push(context, MaterialPageRoute(builder: (context) { return const TwoPageRoute(); })); },)
**提示1:**关于MaterialPageRoute可以理解为对路由界面的一个封装,继承于PageRoute,定义了页面之前跳转的动画,可以针对不同平台,实现与平台页面切换动画风格一致的路由切换动画。
**提示2:**在Flutter中,如果代码是固定的,也就是写死的,编译器会建议加上const。如果你是通过值传递的,那自然就不能加const了。
2.2 参数跳转
界面的跳转中,经常都需要传递参数。下面我们传递一个String参数和一个Bean类
UserBean类
class UserBean{ String name; int age; UserBean(this.name, this.age);}
修改TwoPageRoute页面
class TwoPageRoute extends StatelessWidget { const TwoPageRoute({Key? key, required this.text, // 接收一个text参数 required this.userBean //接收一个userBean类 }) : super(key: key); final String text; final UserBean userBean; @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: const Text("第二个页面"), ), body: Center( child: Column( children: [ Text("接受text值:$text"), Text("接受userBean值:${userBean.toString()}"), ], ), ), ); }}
修改TextButton中的传参
TextButton( child: const Text("通过实例跳转"), onPressed: () { Navigator.push(context, MaterialPageRoute(builder: (context) { return TwoPageRoute( text: "我是第一个页面", userBean: UserBean("小小虫", 18)); })); },)
2.2 接收参数返回
在Flutter,接受页面的返回参数,相比安卓会比较方便,如下:
TextButton( child: const Text("通过实例跳转"), onPressed: () async { var result = await Navigator.push(context, MaterialPageRoute(builder: (context) { return TwoPageRoute( text: "我是第一个页面", userBean: UserBean("小小虫", 18)); })); print("路由返回值: $result"); },)
修改TwoPageRoute页面,添加一个按钮返回参数
TextButton( onPressed: () { Navigator.pop(context, "我是返回值"); }, child: const Text("关闭页面并返回值"))
**注意1:**关键词async和await,不然不会等待页面结束接受返回值。关键词async和await,不然不会等待页面结束接受返回值。
三、路由命名跳转
在Flutter中,页面的跳转除了通过上面的方法外,还有一种通过路由命名跳转,类似于安卓的隐式跳转,安卓的如下:
<action android:name="com.example.SplashActivity" />
而在Flutter中,需要在MyApp中添加routes参数,如下:
void main() { runApp(const MyApp());}class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), //注册路由表 routes: { "custom_page": (context) => const CustomRoute(), }, ); }}
增加一个TextButton,可以看到,路由命名的跳转需要通过pushNamed方法,支持arguments传参,是不是很熟悉的样子👀
TextButton( child: const Text("通过自定义命名路由跳转"), onPressed: () async { var result = await Navigator.pushNamed(context, "custom_page", arguments: "hello,我是通过自定义命名路由跳转"); print("通过自定义命名路由跳转路由返回值: $result"); },)
然后修改CustomRoute页面,在build中获取参数,如下:
@overrideWidget build(BuildContext context) { //获取路由参数 var args=ModalRoute.of(context)?.settings.arguments; }
如果你想两种结合在一起,把TwoPageRoute也加到routes中,还是最好不要吧🤣
修改routes,增加two_page_route
routes: { "two_page_route": (context) { dynamic obj = ModalRoute.of(context)!.settings.arguments; return TwoPageRoute(text: obj["text"],userBean:obj["user"] ,); },}
修改参数,flutter的arguments的类型真的是很百变👍,感觉出问题的几率也会很高。
TextButton( child: const Text("通过自定义命名路由跳转"), onPressed: () async { var result = await Navigator.pushNamed(context, "two_page_route", arguments: { 'text': '我是第一个页面', 'user': UserBean("小小虫", 181), }); print("通过自定义命名路由跳转路由返回值: $result"); },)
四、路由钩子
所谓的路由钩子,其实就是一些路由相关的监听方法(监听就监听,还钩子)。
例如:
- onGenerateRoute:通过命名路由打开是会被调用。注意!重点!重点!是对应的name没有在routes中有映射关系,那么就会执行onGenerateRoute钩子函数,也就是没有在routes中注册路由。
- onUnknowRoute:在打开一个不存在的命名路由时会被调用
- navigatorObservers:监听所有路由跳转动作
举几个栗子
onGenerateRoute使用,在MaterialApp中添加onGenerateRoute,如下:
@override Widget build(BuildContext context) { return MaterialApp( onGenerateRoute: (RouteSettings settings) { var routeName = settings.name; var isLogin = true; if(routeName == "two_page_route" && isLogin){ return MaterialPageRoute(builder: (context) { return TwoPageRoute(text: "我是第一个页面", userBean: UserBean("小小虫", 18)); }); }else{ //登录逻辑。。。 } }, ); }}
**注意:**记得先把two_page_route从routes去掉!
navigatorObservers使用,在MaterialApp中添加navigatorObservers,如下:
@override Widget build(BuildContext context) { return MaterialApp( //监听所有路由跳转动作, navigatorObservers: [ MyNavigator() ], ); }
新建一个MyNavigator类,如下:
import 'package:flutter/widgets.dart';///导航栈的变化监听class MyNavigator extends NavigatorObserver{ @override void didPush(Route route, Route? previousRoute) { super.didPush(route, previousRoute);//监听每个路由进栈 } @override void didPop(Route route, Route? previousRoute) { super.didPop(route, previousRoute); //监听每个路由出栈 }}