Flutter18 Flutter 组件之 导航器 Route 详解

目录

1 简单页面跳转  

2.1 命名 Route 详解

2.2  路由跳转方式之 Push 详解

2.3  Navigator.push 

3 路由跳转方式之 Push 进阶

3.1 pushNamedAndRemoveUntil

3.2 pushReplacementNamed  = startActivity+finsh() 

3.3 popAndPushNamed

4 路由跳转方式之 Pop 详解

4.1 Navigator.pop

4.2 路由跳转方式之 Pop 进阶

5. 初始路由 initialRoute

6. 路由拦截 onGenerateRoute

7. 路由传值

8.1 路由正向传值以及反参接收

8.2 路由接收正向传值以及反向传参

8.3 其他写法


**首先:一个App可能有多个导航器Navigator

MaterialApp内置了一个导航器Navigator

1 简单页面跳转  

Navigator.of(context).pop VS Navigator.pop(context)

Navigator.of(context).push VS Navigator.push(context)

Navigator也是一个Widget    下面就会出现多个导航器

------ Navigator.of(context,rootNavigator)可以指定使用哪个导航器


 class InitPage extends StatelessWidget {
   @override
   Widget build(BuildContext context) {  
    ///直接返回了一个Navigator对象
     return Navigator(
       //初始路由的名字
       initialRoute: 'pageOne',
       onGenerateRoute: (RouteSettings settings) {
         WidgetBuilder builder;
         switch (settings.name) {
           case 'pageOne':
             //pageOne的路由对应的页面
             builder = (BuildContext ctx) => PageOne();
             break;
           case 'pageTwo':
              //pageTwo的路由对应的页面
             builder = (BuildContext ctx) => PageTwo(
               onSignupComplete: () {
               ///PageTwo点击事件,跳转到DefaultPage页面
               //注意这个Navigator.of操作的是MaterialApp的内置Navigator,后面会有说明
                 Navigator.of(context).pop();
               },
             );
             break;
         }
         return MaterialPageRoute(builder: builder, settings: settings);
     );
   }
 }

2.1 命名 Route 详解

import 'package:flutter/material.dart';

class FMMaterialAppVC extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      home: Scaffold(
        body: AAA(),
      ),
      routes: {
        '/bbb': (context) => BBB(),
        '/ccc': (context) => CCC(),
        '/ddd': (context) => DDD(),
      },
    );
  }
}
Navigator.pushNamed(context, '/bbb');
//flutter pop回首页, 不管导航栈有多少路由
Navigator.popUntil(context, (route) => route.isFirst);

2.2  路由跳转方式之 Push 详解

无参数

Navigator.pushNamed(context, '/bbb');

有参数

final datas = {"data": ["1","2","3"]};
Navigator.pushNamed(context, '/bbb', arguments: datas);

2.3  Navigator.push 

无参数

            Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context){
                      return BBB();
                  }
            );

有参数,name 可以用来给路由命名,arguments 用来传递参数

            final datas = {"data": ["1","2","3"]};

            Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context){
                      return BBB();
                  },
                  settings: RouteSettings(
                    name: '/bbb',
                    arguments: datas,
                  ),
                ),
            );

上面代码意思就是跳转到 BBB() 页面,并且给 BBB() 命名为 '/bbb',在路由堆栈中,读取到这个 route 时,route.setting.name 与该命名相同。

3 路由跳转方式之 Push 进阶

2 中是最为常用的页面进出栈,但是在某些场合需要有特殊的处理。
注意:写法大同小异,后续就不在赘述传参方式,均与2相同。

3.1 pushNamedAndRemoveUntil

例如我们页面从AAA->BBB->CCC->DDD,这样进行页面,但是我们希望 CCC 再使用过后就被销毁。使得页面层级变为 AAA-BBB-DDD。

Navigator.of(context).pushNamedAndRemoveUntil('/ddd', (route) => route.settings.name == '/bbb');

跳转到指定页面,并删除前边所有页面

Navigator.of(context).pushNamedAndRemoveUntil('/ddd', (route) => route.isCurrent)
// 等价于下面这行代码
            //Navigator.of(context).pushNamedAndRemoveUntil('/ddd', (route) => route.settings.name == '/ddd');

3.2 pushReplacementNamed  = startActivity+finsh() 

先跳转再处理路径

例如我们页面从AAA->BBB->CCC->DDD,这样进行页面,但是我们希望 CCC 再使用过后就被销毁。使得页面层级变为 AAA-BBB-DDD。

            Navigator.pushReplacementNamed(context, '/ddd');

3.3 popAndPushNamed

先 pop 一级,然后在 push 到对应页面,效果与3.2 相同

            Navigator.popAndPushNamed(context, '/ddd');

4 路由跳转方式之 Pop 详解

Navigator.pop(context);

 判断是否可以 pop

 bool canpop = Navigator.canPop(context);
            if (canpop) Navigator.pop(context);

先判断是否可以 pop,如果可以,在pop,相当于 上边代码

Navigator.maybePop(context);

4.1 Navigator.pop

无参数

            Navigator.pop(context);

有参数

            final data = {"data":["1","2","3"]};
            Navigator.pop(context, data);

4.2 路由跳转方式之 Pop 进阶

4 中是最为常用的页面进出栈,但是在某些场合需要有特殊的处理。pop 进阶方法比较少,只有 popUntil (2.1)与 popAndPushNamed ,在3.3中讲过后者了,这里不重复叙述。

  • 回到栈顶
            Navigator.popUntil(context, (route) => route.isFirst);
  • 回到指定页面

我们使用下方代码回到 BBB 页面 AAA-BBB-CCC-DDD -> AAA-BBB

            Navigator.popUntil(context, (route) => route.settings.name == '/bbb');

5. 初始路由 initialRoute

  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      // home: Scaffold(
      //   body: AAA(),
      // ),
      initialRoute: '/ccc',
      routes: {
        '/aaa': (context) => AAA(),
        '/bbb': (context) => BBB(),
        '/ccc': (context) => CCC(),
        '/ddd': (context) => DDD(),
      },
    );
  }
  • a. 更改 initialRoute 为 routes 表里命名过得路由。

  • b. 设置根路由
    设置路由 '/' ,当初始路由异常时,会停留在根路由。

  • c. 使用未知路由
  •   Widget build(BuildContext context) {
        // TODO: implement build
        return MaterialApp(
          // home: Scaffold(
          //   body: AAA(),
          // ),
          initialRoute: '/cc',
          routes: {
            '/aaa': (context) => AAA(),
            '/bbb': (context) => BBB(),
            '/ccc': (context) => CCC(),
            '/ddd': (context) => DDD(),
          },
          onUnknownRoute: (setting){
            print(setting);
            return MaterialPageRoute(builder: (context) => AAA());
          },
        );
      }

    6. 路由拦截 onGenerateRoute

class FMMaterialAppVC extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      // home: Scaffold(
      //   body: AAA(),
      // ),
      initialRoute: '/',
      routes: {
        '/': (context) => AAA(),
        '/bbb': (context) => BBB(),
        '/ccc': (context) => CCC(),
        '/ddd': (context) => DDD(),
      },
      // onGenerateInitialRoutes: (string){
      //   return [
      //     MaterialPageRoute(builder: (context) => AAA()),
      //   ];
      // },
      onGenerateRoute: (setting){
        print(setting);
        return MaterialPageRoute(builder: (context) => CCC());
      },
      onUnknownRoute: (setting){
        print(setting);
        return MaterialPageRoute(builder: (context) => AAA());
      },
    );
  }
}

应该有很多小伙伴跟我一样,onGenerateRoute 不执行,明明写了 onGenerateRoute 方法,但是却不响应。查了挺多博客,没有相关描述,然后去翻了官方文档和源码,终于找到问题。

onGenerateRoute 路由拦截不能与命名路由一起使用,否则会只执行命名路由,不在进行拦截。下面我们注释掉命名路由,然后通过路由拦截,自定义一套路由跳转,从而实现命名路由的功能。

  Widget build(BuildContext context) {
    // TODO: implement build
    return MaterialApp(
      initialRoute: '/',
      // routes: {
      //   '/': (context) => AAA(),
      //   '/bbb': (context) => BBB(),
      //   '/ccc': (context) => CCC(),
      //   '/ddd': (context) => DDD(),
      // },
      // onGenerateInitialRoutes: (string){
      //   return [
      //     MaterialPageRoute(builder: (context) => AAA()),
      //   ];
      // },
      onGenerateRoute: (setting){
        print(setting);
        final isLogin = true;
        
        final routes = {
          '/': (context) => AAA(),
          '/bbb': (context) => BBB(),
          '/ccc': (context) => CCC(),
          '/ddd': (context) => DDD(),
        };
        
        if (!isLogin) {
           return MaterialPageRoute(builder: (context) => AAA());
        }
        
        return MaterialPageRoute(builder: routes[setting.name], settings: setting);
      },
      onUnknownRoute: (setting){
        print(setting);
        return MaterialPageRoute(builder: (context) => AAA());
      },
    );
  }

7. 路由传值

8.1 路由正向传值以及反参接收

BBB 页面 push 到 CCC,并等待 CCC 回来时的反参。

class BBB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('BBB'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('点击前往CCC'),
          onPressed: (){
            var backValueFromDDD = Navigator.pushNamed(context, '/ccc',arguments: {'value': "我是BBB页面传过来的值"});
            backValueFromDDD.then((value){
              print("CCC 传回来反参了,${value}");
            });
            // Navigator.pushNamedAndRemoveUntil(context, '/ccc', (route) => route.isCurrent);
          },
        ),
      ),
    );
  }
}

我们使用 then 属性来接收下一个页面 pop 回来带的参数。

8.2 路由接收正向传值以及反向传参

我们在 CCC 类中增加以下代码。

  Widget build(BuildContext context) {
    // TODO: implement build
    var value = ModalRoute.of(context).settings.arguments;
    print("BBB 页面带过来参数了,${value}");

    return Scaffold(
      appBar: AppBar(
        title: Text('CCC'),
      ),
      body: _listView(context),
    );
  }
        ListTile(
          title: Text("Navigator.of(context).pop 传参"),
          onTap: (){
            Navigator.of(context).pop({"value":"我是CCC页面带回来的值"});
          },
        ),

8.3 其他写法

在 BBB 中可以尝试以下写法,可以达到相同效果。

class BBB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('BBB'),
      ),
      body: Center(
        child: RaisedButton(
          child: Text('点击前往CCC'),
          onPressed: () async {
            var backValueFromDDD = await Navigator.pushNamed(context, '/ccc',arguments: {'value': "我是BBB页面传过来的值"});
            backValueFromDDD;
            print(backValueFromDDD);
            // Navigator.pushNamedAndRemoveUntil(context, '/ccc', (route) => route.isCurrent);
          },
        ),
      ),
    );
  }
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值