每一个应用都有不少个页面,在flutter中一样也有不少页面,被称之为路由(Router),页面之间的跳转经过导航器(Navigator)进行管理。 其中 Navigator.push 和 Navigator.pop 是最简单的跳转到新页面和返回到上一级界面的方式。程序员
路由分为静态路由(即命名路由)和动态路由。页面之间跳转时每每须要传递参数,这称之为路由传值。下面咱们会一一带领你们学习。app
经过本篇文章的学习咱们的目标是熟练掌握路由及传值,之后进行应用开发时对页面跳转方面再也不疑惑。框架
flutter中万物皆widget,咱们的页面(route)也是widget的子类,因此咱们定义一个界面也是经过继承widget实现。 前面的博客咱们已经定义过界面了,好比计数器实例,就是一个简单的页面,也就是一个路由。下面咱们来详细实现一个界面。 首先我须要一个入口函数,这个相信你们已经很熟悉了,就是在main方法中调用runApp函数进入应用,咱们就不作详细介绍了,直接给出代码。less
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 经常使用固定写法,生成Material风格的App
return MaterialApp(
title: "路由使用",
theme: ThemeData(
// 默认为亮色主题,能够设置[Brightness.dark]变成黑暗模式
brightness: Brightness.light,
),
home: HomePage(), // 首页面
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 经过Scaffold能够方便的生成一个Material风格的页面
return Scaffold(
// 顶部导航栏
appBar: AppBar(
title: Text("主页面"),
),
body: Center(
child: RaisedButton(
child: Text("我是第一个界面,点击我进入第二个界面"),
onPressed: () {
print("我是第一个界面,点击我进入第二个界面");
},
),
),
);
}
}
复制代码
上面的代码是咱们最常规的包含一个主页面的应用。后续咱们写应用时候的基本框架也是在此基础上进行扩展。 如今咱们的想法是点击这个页面上的按钮跳转的第二个界面,首先咱们须要构造第二个界面。构造第二个界面其实和咱们构造第一个 界面HomePage同样,继承widget重写本身想要的样式便可。实现了页面就要开始跳转逻辑。ide
静态路由即命名路由,在经过Navigator进行跳转以前,须要在MaterialApp组件内显式声明路由的名称,一旦声明,路由的跳转 方式就固定了,因此称之为静态路由,有惟一的名称因此也称之为命令路由。显式声明路由经过在MaterialApp内的routes属性进行定义。函数
若是咱们有不少个页面和不少个其余类型的组件都放在lib下,对于后期维护简直是一大折磨,因此分包是大多数平台的常规操做, 就是对有同一种特性的东西放置在同一个包下,好比页面类的组件都放在pages包,工具类的组件放在utils包下等。 接下来咱们就新建一个pages包,把第二个界面SecondPage放进去,把第一个界面HomePage也提取出来放到这个包下。工具
咱们分为一下三步进行静态路由的跳转:学习
import 'package:flutter/material.dart';
// 引入页面路径
import 'pages/HomePage.dart';
import 'pages/SecondPage.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 经常使用固定写法,生成Material风格的App
return MaterialApp(
title: "路由使用",
theme: ThemeData(
// 默认为亮色主题,能够设置[Brightness.dark]变成黑暗模式
brightness: Brightness.light,
),
// 默认加载的页面
initialRoute: '/', // 首页面
// 显式声明界面列表
routes: {
'/': (context) => HomePage(),
'/secondPage': (context) => SecondPage(),
},
);
}
}
复制代码
首页面单独提取出来以后的代码以下。优化
import 'package:flutter/material.dart';
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 经过Scaffold能够方便的生成一个Material风格的页面
return Scaffold(
// 顶部导航栏
appBar: AppBar(
title: Text("主页面"),
),
body: Center(
child: RaisedButton(
child: Text("我是第一个界面,点击我进入第二个界面"),
onPressed: () {
print("我是第一个界面,点击我进入第二个界面");
// 跳转到第二个界面
Navigator.pushNamed(context, '/secondPage');
},
),
),
);
}
}
复制代码
第二个页面提取以后的代码。ui
import 'package:flutter/material.dart';
class SecondPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 经过Scaffold能够方便的生成一个Material风格的页面
return Scaffold(
// 顶部导航栏
appBar: AppBar(
title: Text("第二个界面"),
),
body: Center(
child: RaisedButton(
child: Text("我是第二个界面,点击我进入第二个界面"),
onPressed: () {
print("我是第二个界面,点击我返回到第一个界面");
// 返回上一个界面
Navigator.pop(context);
},
),
),
);
}
}
复制代码
对于命名路由的跳转,经过Navigator.pushNamed方法调用,经过Navigator.pop方法返回上一级界面。
动态路由不须要显示声明,直接经过代码实现。
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 经常使用固定写法,生成Material风格的App
return MaterialApp(
title: "路由使用",
theme: ThemeData(
// 默认为亮色主题,能够设置[Brightness.dark]变成黑暗模式
brightness: Brightness.light,
),
home: HomePage(),
);
}
}
复制代码
在HomePage界面经过调用Navigator.push方法实现跳转。第二个页面的返回逻辑不变。
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SecondPage(),
));
复制代码
有时候咱们不只须要跳转到对应界面,还须要传递一些参数给下一个界面,同时下一个界面返回时,把某些参数再次传递给该界面。 咱们修改SecondPage组件的构造方法,为了接收须要传递的参数。这时候咱们第二个页面结构以下:
class SecondPage extends StatelessWidget {
// 定义一个须要变量, 接收传递的参数
final String title;
// 为title设置一个默认参数,这样的跳转该界面时能够不传值。
SecondPage({Key key, this.title = "第二个界面"});
@override
Widget build(BuildContext context) {
// 经过Scaffold能够方便的生成一个Material风格的页面
return Scaffold(
// 顶部导航栏
appBar: AppBar(
title: Text(title),
),
body: Center(
child: RaisedButton(
child: Text("我是第二个界面,点击我进入第二个界面"),
onPressed: () {
print("我是第二个界面,点击我返回到第一个界面");
// 返回上一个界面
Navigator.pop(context);
},
),
),
);
}
}
复制代码
第一个界面跳转的地方代码是这样的。
Navigator.push(
context,
MaterialPageRoute(
// 传递title为SecondPage,跳转到第二个界面就会把标题设置为SecondPage
builder: (context) => SecondPage(title: "SecondPage"),
));
},
复制代码
说完了从第一个页面往第二个页面传递了参数,若是第二个页面返回时传递一句话,而后第一个页面接收到这句话而后打印出来, 代码修改以下:
// HomePage页面代码
Navigator.push(
context,
MaterialPageRoute(
// 传递title为SecondPage,跳转到第二个界面就会把标题设置为SecondPage
builder: (context) => SecondPage(title: "SecondPage"),
// 调用then等待接收返回数据
)).then((value) => print(value));
// SecondPage页面代码
Navigator.pop(context, "返回传递数据");
复制代码
讲完了动态路由及动态路由传参以后,咱们来说一下静态路由传参,参数的传递方式是flutter为咱们定义好的,咱们只须要把固定 代码拷贝回来,稍微修改便可。为了更具备广泛性,咱们再定义一个页面ThirdPage。
在咱们显示声明了routes以后,还须要在MaterialApp组件内添加onGenerateRoute属性内容进行参数传递的处理。 完整代码以下:
import 'package:flutter/material.dart';
import 'pages/HomePage.dart';
import 'pages/SecondPage.dart';
import 'pages/ThirdPage.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// 声明全部的页面
final routes = {
'/': (context, {arguments}) => HomePage(),
'/secondPage': (context, {arguments}) => SecondPage(),
'/thirdPage': (context, {arguments}) => ThirdPage(arguments: arguments),
};
@override
Widget build(BuildContext context) {
// 经常使用固定写法,生成Material风格的App
return MaterialApp(
title: "路由使用",
theme: ThemeData(
// 默认为亮色主题,能够设置[Brightness.dark]变成黑暗模式
brightness: Brightness.light,
),
// home: HomePage(),
initialRoute: '/', // 默认界面
// 当页面跳转时进行参数处理
onGenerateRoute: (RouteSettings settings) {
// 获取声明的路由页面函数
var pageBuilder = routes[settings.name];
if (pageBuilder != null) {
if (settings.arguments != null) {
// 建立路由页面并携带参数
return MaterialPageRoute(
builder: (context) =>
pageBuilder(context, arguments: settings.arguments));
} else {
return MaterialPageRoute(
builder: (context) => pageBuilder(context));
}
}
return MaterialPageRoute(builder: (context) => HomePage());
},
);
}
}
复制代码
第二个页面传递参数时使用Navigator.pushNamed方法,具体代码以下:
import 'package:flutter/material.dart';
class SecondPage extends StatelessWidget {
// 定义一个须要变量, 接收传递的参数
final String title;
// 为title设置一个默认参数,这样的跳转该界面时能够不传值。
SecondPage({Key key, this.title = "第二个界面"});
@override
Widget build(BuildContext context) {
// 经过Scaffold能够方便的生成一个Material风格的页面
return Scaffold(
// 顶部导航栏
appBar: AppBar(
title: Text(title),
),
body: Center(
child: RaisedButton(
child: Text("我是第二个界面,点击我进入第二个界面"),
onPressed: () {
print("我是第二个界面,点击我进入第三个界面");
// 经过arguments指定参数
Navigator.pushNamed(context, "/thirdPage",
arguments: {'title': "命令路由传递过来的title"});
},
),
),
);
}
}
复制代码
第三个页面获取参数,完整代码以下:
import 'package:flutter/material.dart';
class ThirdPage extends StatelessWidget {
final Map arguments;
// 为title设置一个默认参数,这样的跳转该界面时能够不传值。
ThirdPage({Key key, this.arguments});
@override
Widget build(BuildContext context) {
// 经过Scaffold能够方便的生成一个Material风格的页面
return Scaffold(
// 顶部导航栏
appBar: AppBar(
title: Text("${arguments != null ? arguments['title'] : "ThirdPage"}"),
),
body: Center(
child: RaisedButton(
child: Text("我是第三个界面,点击我进入第二个界面"),
onPressed: () {
print("我是第三个界面,点击我返回到第二个界面");
// 返回上一个界面
Navigator.pop(context, "返回传递数据Page3");
},
),
),
);
}
}
复制代码
上面咱们已经实现了参数的传递,可是routes页面列表和onGenerateRoute比较固定,咱们可以把这两个单独提取出来成为 一个单独的类,这样后期再建立页面或者维护的时候只须要修改这一个类就好了。
咱们新建一个PageConstants类,进行提取,修改后的代码以下:
import 'package:flutter/material.dart';
// 引入页面路径
import '../pages/HomePage.dart';
import '../pages/SecondPage.dart';
import '../pages/ThirdPage.dart';
// 声明全部页面
final routes = {
'/': (context, {arguments}) => HomePage(),
'/secondPage': (context, {arguments}) => SecondPage(),
'/thirdPage': (context, {arguments}) => ThirdPage(arguments: arguments),
};
// 处理参数传递
// ignore: top_level_function_literal_block
var onGenerateRoute = (RouteSettings settings) {
// 获取声明的路由页面函数
var pageBuilder = routes[settings.name];
if (pageBuilder != null) {
if (settings.arguments != null) {
// 建立路由页面并携带参数
return MaterialPageRoute(
builder: (context) =>
pageBuilder(context, arguments: settings.arguments));
} else {
return MaterialPageRoute(
builder: (context) => pageBuilder(context));
}
}
return MaterialPageRoute(builder: (context) => HomePage());
};
复制代码
这时候咱们只须要简单修改MyApp组件便可:
import 'package:flutter/material.dart';
import 'package:hello_flutter/pages/PageConstants.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
// 经常使用固定写法,生成Material风格的App
return MaterialApp(
title: "路由使用",
theme: ThemeData(
// 默认为亮色主题,能够设置[Brightness.dark]变成黑暗模式
brightness: Brightness.light,
),
initialRoute: '/', // 默认界面
// 经过PageConstants引入
onGenerateRoute: onGenerateRoute,
);
}
}
复制代码
这样来看就会清爽不少。
篇幅所限,此次的内容就先讲到这里,下篇文章继续讲日后的内容,应该会单独讲一讲实现仿闲鱼底部tab页面切换和仿头条多tab页切换。
为了第一时间获取最新文章,请关注公众号 -- 程序员指北,每个关注都能让做者多搬一块砖。