Flutter开发之路由与导航的实现

如果说构成视图元素的基本单位是组件,那么构成应用程序的基本单位就是页面。对于拥有多个页面的应用程序而言,如何从一个页面平滑地过渡到另一个页面,是技术框架需要考虑的问题。

在前端开发中,可以使用路由框架来统一管理页面及它们之间的跳转。在Android中路由指的是一个Activity,在iOS中指的是一个ViewController,可以通过startActivity或pushViewController来打开一个新的路由。在Flutter中,路由的管理和导航借鉴了前端和客户端的设计思路,需要使用Route和Navigator来进行统一管理。

其中,Route是页面的抽象,主要负责创建界面、接收参数以及响应导航器Navigator的打开与关闭。而Navigator则用于维护路由栈管理,Route打开即入栈,Route关闭即出栈,当然还可以替换栈内的某一个Route。作为官方提供的路由管理组件,Navigator提供了一系列方法来管理路由栈,其中最常用的两个方法是push()和pop(),它们的含义如下。

  • push():将给定的路由入栈,返回值是一个Future对象,用以接收路由出栈时的返回数据。
  • pop():将栈顶路由出栈,返回结果为页面关闭时返回给上一个页面的数据。

除了push()和pop()方法外,Navigator还提供了很多其它实用的方法,如replace()、removeRoute()和popUntil()等,可以根据使用场景合理的选取。

根据是否需要提前注册页面标识符,Flutter中的路由管理可以分为基本路由和命名路由两种。

  • 基本路由:无需提前注册,在页面切换时需要手动构造页面的实例。
  • 命名路由:需要提前注册页面标识符,在页面切换时通过标识符直接打开新的路由。

下面就让我们重点来看一下Flutter中的路由管理的基本路由和命名路由等相关知识。

基本路由

在Flutter开发中,基本路由的使用方式和原生Android、iOS打开新页面的方式非常类似。要打开一个新的页面,只需要创建一个MaterialPageRoute对象实例,然后调用Navigator.push()方法将新页面压到路由堆栈的顶部即可,如果要返回上一个页面,则可以调用Navigator.pop()方法。

其中,MaterialPageRoute是一种路由模板,定义了路由创建以及路由切换过渡动画的相关配置,该配置可以根据不同的平台实现与平台页面切换动画风格一致的路由切换动画。下面是使用Navigator实现页面跳转的示例,代码如下。

class FirstPage extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return Scaffold(
  appBar: AppBar(
  title: Text('第一个页面'),),body: Center(
  child: RaisedButton(
   child: Text('跳转到第二个页面'),onPressed: () => Navigator.push(context,MaterialPageRoute(builder: (context) => SecondPage()))),);
 }
}

class SecondPage extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
 return Scaffold(
  appBar: AppBar(
  title: Text('第二个页面'),body: Center(
  child: RaisedButton(
   child: Text('返回上一个页面'),onPressed: () => Navigator.pop(context)),);
 }
}

在上面的示例中,我们创建了两个页面,每个页面都包含一个按钮。当点击第一个页面上的按钮时将导航到第二个页面,点击第二个页面上的按钮将返回第一个页面。运行上面的代码,效果如下图所示。


要实现上面的示例效果,首先需要新建一个底部导航栏,然后再由底部导航栏去嵌套其他子路由。关于底部导航栏的实现,可以直接使用Scaffold布局组件的bottomNavigationBar属性实现,如下所示。

class MainPage extends StatefulWidget {
 @override
 State<StatefulWidget> createState() {
 return MainPageState();
 }
}

class MainPageState extends State<MainPage> {
 int currentIndex = 0;  //底部导航栏索引
 final List<Widget> children = [
 HomePage(),//首页
 MinePage(),//我的
 ];

 @override
 Widget build(BuildContext context) {
 return Scaffold(
  body: children[currentIndex],bottomNavigationBar: BottomNavigationBar(
  onTap: onTabTapped,currentIndex: currentIndex,items: [
   BottomNavigationBarItem(icon: Icon(Icons.home),title: Text('首页')),BottomNavigationBarItem(icon: Icon(Icons.person),title: Text('我的')),],);
 }

 void onTabTapped(int index) {
 setState(() {
  currentIndex = index;
 });
 }
}

然后,每个底部导航栏会嵌套一个子路由,然后子路由再去管理对应的路由页面。在Flutter中,创建子路由需要使用Navigator组件,并且子路由的拦截需要使用onGenerateRoute属性,如下所示。

class HomePage extends StatelessWidget {

 @override
 Widget build(BuildContext context) {
 return Navigator(
  initialRoute: 'first',onGenerateRoute: (RouteSettings settings) {
  WidgetBuilder builder;
  switch (settings.name) {
   case 'first':
   builder = (BuildContext context) => FirstPage();
   break;
   case 'second':
   builder = (BuildContext context) => SecondPage();
   break;
  }
  return new MaterialPageRoute(builder: builder,settings: settings);
  },);
 }
}

运行上面的代码,当点击子路由页面上的按钮时,底部的导航栏栏并不会消失,这是因为子路由仅在自己的范围内有效。要想跳转到其他子路由管理的页面,就需要在根导航器中进行注册,也就是MaterialApp内部的导航器。

路由传参

在移动应用开发中,页面参数的传递也是一个比较常见的需求。为了满足不同场景下页面跳转过程中参数传递的需求,Flutter提供了路由参数机制,可以在打开路由时传递参数,然后在目标页面通过RouteSettings来获取页面传递的参数,如下所示。

Navigator.of(context).pushNamed("second ",arguments: " from first page");

class SecondPage extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
//取出路由参数
 String msg = ModalRoute.of(context).settings.arguments as String;
  … //数据处理
 }
}

除此之外,对于某些特定的页面,还需要在其关闭时回传页面处理的处理结果。这与Android提供的startActivityForResult()方法监听目标页面返回处理结果的场景类似,Flutter也提供了页面返回的参数机制。具体来说,就是在使用push()方法打开目标页面时,可以设置目标页面关闭时监听函数来获取返回参数,当目标页面关闭路由时使用pop()方法回传参数即可。例如,下面是两个页面之间参数值传递和参数值回传,代码如下。

class FirstPage extends StatefulWidget {
 @override
 State<StatefulWidget> createState() {
 return FirstPageState();
 }
}

class FirstPageState extends State<FirstPage> {

String result = '';

 @override
 Widget build(BuildContext context) {
 return Scaffold(
  body: Center(
   child: Column(
  children: <Widget>[
   Text('from seconde page: ' + result,style: TextStyle(fontSize: 20)),RaisedButton(
    child: Text('跳转'),//使用then()获取目标页面返回参数
    onPressed: () => Navigator.of(context)
     .pushNamed("second",arguments: "from first page")
     .then((msg) => setState(() => result = msg)))
  ],)),);
 }
}

class SecondPage extends StatelessWidget {
 @override
 Widget build(BuildContext context) {

 String msg = ModalRoute.of(context).settings.arguments as String;

 return Scaffold(
  body: Center(
   child: Column(children: [
   Text('from first screen: ' + msg,RaisedButton(
    child: Text('返回'),onPressed: () => Navigator.pop(context,"from second page"))
   ]),));
 }
}

运行上面的代码,可以看到,当SecondPage页面被关闭重新回到FirstPage页面时,FirstPage会把回传的参数值展示出来,最终效果如下图所示。

以上是来客网为你收集整理的Flutter开发之路由与导航的实现全部内容,希望文章能够帮你解决Flutter开发之路由与导航的实现所遇到的程序开发问题。

如果觉得来客网网站内容还不错,欢迎将来客网网站推荐给程序员好友。