Flutter基础: 路由管理

作者: 白袍君 | 来源:发表于2019-06-10 23:15 被阅读21次

    Flutter的设计貌似对前端同学比较友好,言归正传,先从原理开始,然后是具体的case,好,我们开始:

    小提示:电脑端阅读更佳

    1. 路由工作原理:

    对于原来移动端开发的同学,多了件事情,管理路由。简单讲路由的工作原理是通过路由对象的进出栈来使用户从一个页面跳转到另一个页面。

    2. 路由是什么?

    在Flutter 中理解好路由(Route), 离不开另一个概念导航(Navigator), Flutter中路由管理, 主要依赖的是 Navigator(导航器)类, 这是一个用于管理一组具有某种进出规则的页面的 Widget, 也就是说用它我们能够实现各个页面间有规律的切换, 而这里的规则便是在其内部维护的一个“ 路由栈。

    3. 路由的种类:

    路由分为 组件路由,命名路由,自定义路由,嵌套路由。

    4. 使用方法:

    Navigator:导航器,负责管理路由
    路由名称命名:路由名称通常使用路径结构:“/a/b/c”,主页默认为 “/”。

    4.1 PUSH 使用

    1. pushNamed
    Navigator.of(context).pushNamed('routeName');
    简单的将我们需要进入的页面push到栈顶,以此来显示当前页面,其参数是一个字符串类型,传入的是页面对应的路由名称 该路由名称需要在程序主入口中进行定义:

    void main() {
      runApp(
        new MaterialApp(
             home: new Screen1(),
             routes: <String, WidgetBuilder> {
              '/screen1': (BuildContext context) => new Screen1(),
              '/screen2': (BuildContext context) => new Screen2(),  
              '/screen3': (BuildContext context) => new Screen3(),
     },   ));}
    

    2.pushReplacementNamed
    Navigator.of(context).pushReplacementNamed('routeName');

    指把当前页面在栈中的位置替换成跳转的页面(替换导航器的当前路由,通过推送路由[routeName]),当新的页面进入后,之前的页面将执行dispose方法。

    下面为官方说明:
    Replace the current route of the navigator that most tightly encloses the given context by pushing the route named [routeName] and then disposing the previous route once the new route has finished animating in.

    Case Study:
    从SplashScreen到HomeScreen。它应该只显示一次,用户不应该再从主屏幕回到它。在这种情况下,由于我们将要进入一个全新的屏幕, 我们可能想要使用这个方法来实现它的enter animation属性。

    3.pushReplacement
    特点:可以通信,页面间传递参数

    Navigator.pushReplacement( context, MaterialPageRoute(builder: (BuildContext context) => screen4(param)));

    4. popAndPushNamed
    Navigator.popAndPushNamed(context, 'routeName');

    指把当前页面在栈中的位置替换成跳转的页面(替换导航器的当前路由,通过推送路由[routeName]),当新的页面进入后,之前的页面将执行dispose方法。

    下面为官方说明:
    Replace the current route of the navigator that most tightly encloses the given context by pushing the route named [routeName] and then disposing the previous route once the new route has finished animating in.

    Case Study:
    例如 在购物应用中,有产品列表,用户在产品列表中可以通过筛选,来进一步选择商品,在这个过程中,用户点击筛选按钮时,会进入筛选条件选择界面,当用户点击 确定筛选按钮时,应弹出筛选界面,并使用新的筛选条件进入产品列表。这种情况popAndPushNamed就更合适了。

    5. pushNamedAndRemoveUntil
    Navigator.of(context).pushNamedAndRemoveUntil('routeName', (Route<dynamic> route) => false);

    指将制定的页面加入到路由中,然后将其他所有的页面全部pop, (Route route) => false将确保删除推送路线之前的所有路线。 这时候将打开一个新的routeName页

    Case Study:
    使用情况:例如 当用户点击了退出登录时,我们需要进入某一个页面(比如点退出登录后进入了登录页),这个时候用户点击返回时不应该能进入任何一个页面,这种情况就可以使用。

    6. pushAndRemoveUntil
    Navigator.pushAndRemoveUntil( context, MaterialPageRoute(builder: (BuildContext context) => new screen4()), ModalRoute.withName('/'))

    7. popUntil
    Navigator.popUntil(context, ModalRoute.withName('routeName'));

    4.2 POP 使用

    1. maybePop
    Navigator.of(context).maybePop();

    maybePop 会自动进行判断,如果当前页面pop后,会显示其他页面,不会出现问题,则将执行当前页面的pop操作 否则将不执行。

    Case Study:
    如果我们在初始路由上并且有人错误地试图弹出这个唯一页面怎么办? 弹出堆栈中唯一的页面将关闭您的应用程序,因为它后面已经没有页面了。这显然是不好的体验。 这就是 maybePop() 起的作用。

    2.canPop
    Navigator.of(context).canPop();

    canPop 判断当前页面能否进行pop操作,并返回bool值

    3.pop
    Navigator.of(context).pop();

    直接退出当前页面

    4.3 Popup routes(弹出路由)

    路由不一定要遮挡整个屏幕

    4.4 自定义路由

    创建自己的一个窗口z组件库路由类(如 PopupRoute,ModalRoute 或 PageRoute)的子类
    可以做什么:
    - 动画
    - 路径的动画
    - 路径的模态屏障的颜色
    - 行为以及路径的其他各个特性

    Navigator.push(context, PageRouteBuilder(
    
      opaque: false, //这个属性不会遮挡屏幕
    
      pageBuilder: (BuildContext context, _, __) {return Center(child: Text('My PageRoute'));},
     
      transitionsBuilder: (___, Animation<double> animation, ____, Widget child) {
    
      return FadeTransition(
    
         opacity: animation,
    
         child: RotationTransition(
    
             turns: Tween<double>(begin: 0.5, end: 1.0).animate(animation),
    
             child: child,),
    
    );}));
    
    4.5 嵌套路由

    一个应用程序可以使用多个路由导航器。将一个导航器嵌套在另一个导航器下方可用于创建“内部旅程”

    4.6 数据传递和数据返回(页面间的通信)

    1. 数据传递
    Navigator.push(context, new MaterialPageRoute(builder: (BuildContext context) => new mainPage(params)));

    • 在需要接收参数的页面进行参数定义
    • 将参数添加到构造函数中
    • 使用MaterialPageRoute并在页面中传入参数即可

    2.数据返回

    2.1 Navigator.of(context).pop('这是页面5返回的参数'); 在pop中写上返回的的值,这时候在上方的then中即可得到返回的数据。

    2.2

    方法一:

    String userName = "yinll";
    Navigator.push( context, new MaterialPageRoute( 
          builder: (BuildContext context) => 
            new Screen5(userName)))
            .then(
                (data){ result =data; print(result); 
    });
    

    方法二:

    onTap: () async {
             String result = await Navigator.push( context, new MaterialPageRoute( 
                    builder: (context) => new ContentScreen(articles[index]), ), );
                    if (result != null) { 
                        Scaffold.of(context).showSnackBar( 
                                new SnackBar( content: new Text("$result"), duration: const Duration(seconds: 1), ), ); 
    }}
    
    最佳实践(实用):
    1. 认识路由,一个轻量级的路由管理本质是页面标识(页面路径)与页面实例的映射

    2. 传统的做法弊端

      1. 每个映射的维护影响全局映射配置的稳定性,每次维护映射管理时需要脑补所有的逻辑分支.

      2. 无法做到页面的统一抽象,页面的构造器和构造逻辑被开发者自定义.

      3. 映射配置无法与页面联动,把页面级的配置进行中心化的维护,导致维护责任人缺失.

    3. 最佳实践:路由注解方案(这里是一位阿里同学给出的方案)

      1. annotation_route

      2. 注解方案设计图


        image.png

    参考链接:

      [https://medium.com/flutter-community/flutter-push-pop-push-1bb718b13c31](https://medium.com/flutter-community/flutter-push-pop-push-1bb718b13c31)
    
      [https://juejin.im/post/5be2d6546fb9a049be5cf6d5#heading-0](https://juejin.im/post/5be2d6546fb9a049be5cf6d5#heading-0)
    
      [https://juejin.im/post/5bbaf7bf5188255c8d0fe309#heading-9](https://juejin.im/post/5bbaf7bf5188255c8d0fe309#heading-9)
    
      [https://blog.csdn.net/mayness/article/details/85762966](https://blog.csdn.net/mayness/article/details/85762966)
    

    相关文章

      网友评论

        本文标题:Flutter基础: 路由管理

        本文链接:https://www.haomeiwen.com/subject/thlxfctx.html