Flutter入门第二步-路由管理

Flutter入门第二步-路由管理

1.页面跳转

2.路由

3.命名路由

4.路由生成钩子

说到路由,我们在学习计算机网络的时候也学过一个路由,不过此路由非彼路由。不过单从功能含义的角度来说,两者还是比较相似的。
路由(Route)在移动开发中通常指页面(Page),这跟web开发中单页应用的Route概念意义是相同的,Route在Android中通常指一个Activity。
Flutter中的路由管理和原生开发类似,无论是Android还是iOS,导航管理都会维护一个路由栈,路由入栈(push)操作对应打开一个新页面,路由出栈(pop)操作对应页面关闭操作,而路由管理主要是指如何来管理路由栈。
.
.

1.一个小栗子如何进行页面跳转
在Android原生开发中,我们总会做页面跳转。现在我们在Flutter中,也学一下如何进行页面跳转。
在我们的计数器的例子中,我们下入下边的代码:

class NewRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("New route"),
      ),
      body: Center(
        child: Text("This is new route"),
      ),
    );
  }
}

这个类继承自StatelessWidget,毫无疑问它是一个父widget。我们给它添加了Appbar,设置了title,在屏幕中央提示了"This is new route"。
然后我们在_MyHomePageState.build方法中的Column的子widget中添加一个按钮(FlatButton):

Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: <Widget>[
      ... //省略无关代码

//以下代码
      FlatButton(
         child: Text("open new route"),
         textColor: Colors.blue,
         onPressed: () {
          //导航到新路由   
          Navigator.push( context,
           MaterialPageRoute(builder: (context) {
              return NewRoute();
           }));
          },
         ),
        //以上代码 
       ],
 )

,然后我们重新热同步APP,然后点击那个按钮,就会跳转到一个新的页面。

2. Navigator
Navigator是一个路由管理的组件,它提供了打开和退出路由页方法。Navigator通过一个栈来管理活动路由集合。通常当前屏幕显示的页面就是栈顶的路由。Navigator提供了一系列方法来管理路由栈,在此我们只介绍其最常用的两个方法:

Future push(BuildContext context, Route route)

bool pop(BuildContext context, [ result ])

一个小栗子:在页面之间传递参数(路由传值),我们新建一个理由页面:

class TipRoute extends StatelessWidget {
  TipRoute({
    Key key,
    @required this.text,  // 接收一个text参数
  }) : super(key: key);
  final String text;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("提示"),
      ),
      body: Padding(
        padding: EdgeInsets.all(18),
        child: Center(
          child: Column(
            children: <Widget>[
              Text(text),
              RaisedButton(
                onPressed: () => Navigator.pop(context, "我是返回值"),
                child: Text("返回"),
              )
            ],
          ),
        ),
      ),
    );
  }
}

然后下边的是跳转到新路由页面的代码;

class RouterTestRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: RaisedButton(
        onPressed: () async {
          // 打开`TipRoute`,并等待返回结果
          var result = await Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) {
                return TipRoute(
                  // 路由参数
                  text: "我是提示xxxx",
                );
              },
            ),
          );
          //输出`TipRoute`路由返回结果
          print("路由返回值: $result");
        },
        child: Text("打开提示页"),
      ),
    );
  }
}

我们可以重新写一个入门,或者直接在上面页面跳转的例子上作出更改即可。

3.命名路由
所谓“命名路由”(Named Route)即有名字的路由,我们可以先给路由起一个名字,然后就可以通过路由名字直接打开新的路由了,这为路由管理带来了一种直观、简单的方式。

Flutter中路由表的结构是这样的:

Map<String, WidgetBuilder> routes;

路由表的注册方式很简单,我们回到之前“计数器”的示例,然后在MyApp类的build方法中找到MaterialApp,添加routes属性,代码如下:

MaterialApp(
  title: 'Flutter Demo',
  theme: ThemeData(
    primarySwatch: Colors.blue,
  ),
  //注册路由表
  routes:{
   "new_page":(context) => NewRoute(),
    ... // 省略其它路由注册信息
     //  "/":(context) => MyHomePage(title: 'Flutter Demo Home Page'), //注册首页路由
  } ,
  home: MyHomePage(title: 'Flutter Demo Home Page'),//标记主页
);

现在我们就完成了路由表的注册。上面的代码中home路由并没有使用命名路由,如果我们也想将home注册为命名路由应该怎么做呢?其实很简单,直接将代码中的“注册首页路由解除注释没然后将下方标记主页的这一行注释掉即可。
然后我们就可以用命名路由来进行跳转了,直接在想执行跳转任务的地方加入一行代码:

Navigator.pushNamed(context, "new_page");

即可。“new_page”是我们在上方路由表中注册过的命名。

在上方我们看到了普通情况下怎么传递参数,现在我们看下在使用命名路由的时候怎么传递参数:

首先我们看一下目标页面

class EchoRoute extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    //获取路由参数
    var args=ModalRoute.of(context).settings.arguments;
    //...省略无关代码
    print(args);
    return Scaffold(
      appBar: AppBar(
        title: Text("hahah"),
      ),
      body: (
      Center(
        child: (
            Text(args)
        ),
      )
      ),
    );
  }
}

我们先将上方的命名路由改成我们现在这个,然后我们在跳转的地方这样调用:

Navigator.of(context).pushNamed("new_page",arguments: "hi");

这样我们的参数就传递过来了。
在这里插入图片描述
假设我们也想将上面路由传参示例中的TipRoute路由页注册到路由表中,以便也可以通过路由名来打开它。但是,由于TipRoute接受一个text 参数,我们如何在不改变TipRoute源码的前提下适配这种情况?其实很简单:

MaterialApp(
  ... //省略无关代码
  routes: {
   "tip2": (context){
   //将我们本页面的参数放到构造函数中
     return TipRoute(text: ModalRoute.of(context).settings.arguments);
   },
 }, 
);

4.路由生成钩子
假设我们要开发一个电商APP,当用户没有登录时可以看店铺、商品等信息,但交易记录、购物车、用户个人信息等页面需要登录后才能看。为了实现上述功能,我们需要在打开每一个路由页前判断用户登录状态!如果每次打开路由前我们都需要去判断一下将会非常麻烦,那有什么更好的办法吗?答案是有!

MaterialApp有一个onGenerateRoute属性,它在打开命名路由时可能会被调用,之所以说可能,是因为当调用Navigator.pushNamed(…)打开命名路由时,如果指定的路由名在路由表中已注册,则会调用路由表中的builder函数来生成路由组件;如果路由表中没有注册,才会调用onGenerateRoute来生成路由。onGenerateRoute回调签名如下:

Route Function(RouteSettings settings)
有了onGenerateRoute回调,要实现上面控制页面权限的功能就非常容易:我们放弃使用路由表,取而代之的是提供一个onGenerateRoute回调,然后在该回调中进行统一的权限控制,如:

MaterialApp(
  ... //省略无关代码
  onGenerateRoute:(RouteSettings settings){
      return MaterialPageRoute(builder: (context){
           String routeName = settings.name;
       // 如果访问的路由页需要登录,但当前未登录,则直接返回登录页路由,
       // 引导用户登录;其它情况则正常打开路由。
     }
   );
  }
);

注意,onGenerateRoute只会对命名路由生效。

发布了47 篇原创文章 · 获赞 15 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41525021/article/details/104358087