开启一个新路由
创建一个TipRoute路由,它接受一个提示文本参数,负责将传入它的文本显示在页面上,另外TipRoute中我们添加一个“返回”按钮,点击后在返回上一个路由的同时会带上一个返回参数
import 'package:flutter/material.dart'; //导包
//应用入口
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: '我是标题',
theme: ThemeData(
primarySwatch: Colors.blue,//蓝色主题
),
home: MyHomePage(title: '我是HomePager标题名字'),
);
}
}
//首页,继承自有状态组件
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'点击进行累加~',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.display1,
),
FlatButton(
child: Text("打开新的路由"),
textColor: Colors.blue,
onPressed: (){
//导航到新的路由
Navigator.push(context,MaterialPageRoute(builder: (context){
return NewRoute();
}));
},
),
FlatButton(
child: Text("打开新的路由2"),
textColor: Colors.amber,
onPressed: (){
//导航到第二个路由
Navigator.push(context, MaterialPageRoute(builder: (context){
return NewRoute2();
}));
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
class NewRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.green,
title: Text("new Route"),
),
body: Center(
child: Text("This is new Route"),
),
);
}
}
class NewRoute2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.red,
title: Text("第二个页面"),
),
body: Center(
child: Text("第二个页面的内容"),
),
);
}
}
MaterialPageRoute
MaterialPageRoute({
WidgetBuilder builder,
RouteSettings settings,
bool maintainState = true,
bool fullscreenDialog = false,
})
builder
是一个WidgetBuilder类型的回调函数,它的作用是构建路由页面的具体内容,返回值是一个widget。我们通常要实现此回调,返回新路由的实例。settings
包含路由的配置信息,如路由名称、是否初始路由(首页)。maintainState
:默认情况下,当入栈一个新路由时,原来的路由仍然会被保存在内存中,如果想在路由没用的时候释放其所占用的所有资源,可以设置maintainState
为false。fullscreenDialog
表示新的路由页面是否是一个全屏的模态对话框,在iOS中,如果fullscreenDialog
为true
,新页面将会从屏幕底部滑入(而不是水平方向)。
Navigator
两个方法:
Future push(BuildContext context, Route route)
将给定的路由入栈(即打开新的页面),返回值是一个Future
对象,用以接收新路由出栈(即关闭)时的返回数据。
bool pop(BuildContext context, [ result ])
将给定的路由入栈(即打开新的页面),返回值是一个Future
对象,用以接收新路由出栈(即关闭)时的返回数据。
Navigator执行寻找路由顺序是 initialRoute -> onGenerateRoute -> onUnknownRoute
将给定的路由入栈(即打开新的页面),返回值是一个Future
对象,用以接收新路由出栈(即关闭)时的返回数据。
Navigator.push(BuildContext context, Route route)等价于Navigator.of(context).push(Route route)
路由传值
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "页面1",
theme: ThemeData(
primarySwatch: Colors.red,
),
home: Scaffold(
appBar: AppBar(
title: Text("页面1"),
),
body: GiveRoute(),
),
);
}
}
class GiveRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Center(
child: RaisedButton(
onPressed: () async {
//打开新页面,并且等待返回结果
var result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return TipRoute(
text: "我是传递给TipRoute的文本",
);
},
),
);
print("路由的返回数据为$result");
},
child: Text("打开提示页面"),
),
);
}
}
/**
* 返回数据的
*/
class TipRoute extends StatelessWidget {
final String text;
TipRoute({Key key, @required this.text}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("提示信息"),
),
body: Padding(
padding: EdgeInsets.all(18),
child: Column(
children: <Widget>[
Text(text),
RaisedButton(
onPressed: () => Navigator.pop(context, "我是返回值"),
child: Text("返回"),
),
],
),
),
);
}
}
通过构造函数传值到第二个Route
第二个Route通过Navigator.pop(context, “我是返回值”),向第一个Route返回传值
第一个Route通过下面这段代码来接受数据
return Center(
child: RaisedButton(
onPressed: () async {
//打开新页面,并且等待返回结果
var result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) {
return TipRoute(
text: "我是传递给TipRoute的文本",
);
},
),
);
print("路由的返回数据为$result");
},
child: Text("打开提示页面"),
),
);
命名路由
“命名路由”(Named Route)即有名字的路由
路由表
要想使用命名路由,我们必须先提供并注册一个路由表(routing table),这样应用程序才知道哪个名字与哪个路由组件相对应。其实注册路由表就是给路由起名字,路由表的定义如下:
Map<String, WidgetBuilder> routes;
它是一个Map
,key为路由的名字,是个字符串;value是个builder
回调函数,用于生成相应的路由widget。
根据路由名字在路由表中查找到对应的WidgetBuilder
回调函数,然后调用该回调函数生成路由widget并返回。
使用命名路由
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "路由表 - 命名路由",
theme: ThemeData(
primarySwatch: Colors.amber,
),
routes: {
"/": (context) => HomeDemo(title: "主页"), //使用命名路由 注册首页路由
"new_page1": (context) => PageRoutes1(),
"new_page2": (context) => PageRoutes2(),
},
);
}
}
class HomeDemo extends StatelessWidget {
String title;
HomeDemo({Key key, @required this.title}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("主页"),
),
body: Center(
child: Column(
children: <Widget>[
RaisedButton(
onPressed: () {
Navigator.pushNamed(context, "new_page1");
},
child: Text("通过命名路由方式跳转到page1"),
),
RaisedButton(
onPressed: () {
Navigator.pushNamed(context, "new_page2");
},
child: Text("通过命名路由方式跳转到page2"),
),
],
),
),
);
}
}
class PageRoutes1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("页面一"),
),
);
}
}
class PageRoutes2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("页面二"),
),
);
}
}
通过命名路由注册主页
routes: {
"/": (context) => HomeDemo(title: "主页"), //使用命名路由 注册首页路由
"new_page1": (context) => PageRoutes1(),
"new_page2": (context) => PageRoutes2(),
},
命名路由传递参数
import 'package:first_flutter_app/main.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "命名路由传递参数",
theme: ThemeData(
primarySwatch: Colors.blue,
),
routes: {
"/": (context) => HomeDemo(),
"newpage": (context) => NewPageRoute(),
},
);
}
}
class HomeDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("命名路由传递参数"),
backgroundColor: Colors.amberAccent,
),
body: Center(
child: RaisedButton(
onPressed: () {
Navigator.of(context).pushNamed("newpage", arguments: "项目ID1234");
},
child: Text("命名路由 传递函数"),
),
),
);
}
}
class NewPageRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
var args = ModalRoute.of(context).settings.arguments;
return Scaffold(
appBar: AppBar(
title: Text("NewPageRoute"),
backgroundColor: Colors.amberAccent,
),
body: Center(
child: Text("命名路由接受到的参数:$args"),
),
);
}
}
有构造和无构造的命名路由
import 'package:first_flutter_app/main.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
title: "命名路由传递参数",
theme: ThemeData(
primarySwatch: Colors.blue,
),
routes: {
"/": (context) => HomeDemo(),
"newpage": (context) => NewPageRoute(), //无构造的
"tiproute": (context) =>
TipRoute(text: ModalRoute.of(context).settings.arguments), //有构造的
},
);
}
}
class HomeDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("命名路由传递参数"),
backgroundColor: Colors.amberAccent,
),
body: Center(
child: Column(
children: <Widget>[
RaisedButton(
onPressed: () {
Navigator.of(context)
.pushNamed("newpage", arguments: "项目ID1234");
},
child: Text("命名路由无构造的 传递函数"),
),
RaisedButton(
onPressed: () {
Navigator.of(context)
.pushNamed("tiproute", arguments: "你好,我是flutter命名函数传值");
},
child: Text("命名路由有构造的 传递函数"),
)
],
),
),
);
}
}
/**
* 无构造的
*/
class NewPageRoute extends StatelessWidget {
@override
Widget build(BuildContext context) {
var args = ModalRoute.of(context).settings.arguments;//本行是接受参数
return Scaffold(
appBar: AppBar(
title: Text("NewPageRoute"),
backgroundColor: Colors.amberAccent,
),
body: Center(
child: Text("命名路由接受到的参数:$args"),
),
);
}
}
/**
* 有构造的
*/
class TipRoute extends StatelessWidget {
final String text; //用来接受传过来的信息
TipRoute({Key key, @required this.text}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("提示信息"),
),
body: Padding(
padding: EdgeInsets.all(18),
child: Column(
children: <Widget>[
Text(text),
RaisedButton(
onPressed: () => Navigator.pop(context, "我是返回值"),
child: Text("返回"),
),
],
),
),
);
}
}
路由生成钩子
通过 onGenerateRoute()
函数提取参数,然后把参数传递给组件
开发一个电商APP,当用户没有登录时可以看店铺、商品等信息,但交易记录、购物车、用户个人信息等页面需要登录后才能看。为了实现上述功能,我们需要在打开每一个路由页前判断用户登录状态!如果每次打开路由前我们都需要去判断一下将会非常麻烦。
MaterialApp有一个onGenerateRoute属性,它在打开命名路由时可能会被调用,
之所以说可能,是因为当调用Navigator.pushNamed(…)打开命名路由时,如果指定的路由名在路由表中已注册,则会调用路由表中的builder函数来生成路由组件;如果路由表中没有注册,才会调用onGenerateRoute来生成路由。
onGenerateRoute
回调签名如下:
Route<dynamic> Function(RouteSettings settings)
MaterialApp(
... //省略无关代码
onGenerateRoute:(RouteSettings settings){
return MaterialPageRoute(builder: (context){
String routeName = settings.name;
// 如果访问的路由页需要登录,但当前未登录,则直接返回登录页路由,
// 引导用户登录;其它情况则正常打开路由。
}
);
}
);