宁泽林_NiZerin - 互联网技术博客

  • PHP
  • Go
  • Java
  • Rust
  • Python
  • 交流群
  • 关于我
  • 留言版
  1. 首页
  2. Flutter
  3. 正文

Flutter 基础(十二)路由(页面跳转)与数据传递

2019年9月19日 1878点热度 0人点赞 3条评论

前言

在 Android 开发中我们使用 Intent 来进行页面跳转,也称之为原生路由,后来出现了一些路由框架,比如 ARouter。
在 Flutter 中进行界面跳转的就是路由,路由用 Route 类来进行表示,Navigator 是对 Route 进行管理的 Widget。这一篇文章我们来学习路由和数据传递。flutter 路由的使用方式主要有两种,一种是新建路由,一种是注册路由。

1. 新建路由

创建两个页面,第一个页面有一个按钮,点击这个按钮跳到第二个页面。先来实现第一个页面:

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(), maintainState: false));
          },
        ),
      ),
    );
  }
}

通过 Navigator.push () 方法将一个 Route 对象添加到 Navigator 管理的 Route 堆栈中,这里的 Route 对象是一个 MaterialPageRoute,它自带页面切换动画,并且适配了 Android 和 iOS,如果是 Android,页面进入动画是向上滑动并淡出,退出是相反的;如果是 iOS,页面进入动画是从右侧滑入,退出同样是相反的。一般来说使用 MaterialPageRoute 就够用了,如果不满足需求,可以实现自定义 Route。
接着来实现第二个页面,代码如下所示。

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);
          },
        ),
      ),
    );
  }
}

Navigator.pop () 方法用于关闭当前页面,返回上一个页面,并将当前的 Route 对象从 Navigator 管理的 Route 堆中移除。
完整的代码如下所示。

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter",
      home: FirstPage(),
    );
  }
}
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(),
                maintainState: false,
              ),
            );
          },
        ),
      ),
    );
  }
}
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);
          },
        ),
      ),
    );
  }
}

运行程序,效果如下所示。

Zc1mCt.png

2. 使用注册路由

如果很多页面都跳转到了同一个页面,每次都要新建路由,那么会写很多重复的代码,使用注册路由就可以简化。

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter",
      initialRoute: '/First',//1
      routes: {
        '/First': (context) => FirstPage(),
        "/Second": (context) => SecondPage()
      },
      home: FirstPage(),
    );
  }
}
class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("第一页"),
      ),
      body: Center(
        child: RaisedButton(
          child: Text("跳转到第二页"),
          onPressed: () {
            Navigator.pushNamed(context, '/Second');//2
          },
        ),
      ),
    );
  }
}
...

省略了第二页的代码,因为没有什么变化。改变的是我们需要定义路由表,路由表的格式为 Map<String, WidgetBuilder> routes; 其中 key 为路由名称,value 是 builder 回调函数,用于生成相应的路由 Widget。通过路由名称入栈新路由时,应用会根据路由名称在路由表中找到对应的 WidgetBuilder 回调函数,通过调用该回调函数生成路由 widget 并返回。
注释 1 处用来定义初始路由的页面,接着注册路由表,里面包含了两个页面,分别是 FirstPage 和 SecondPage。
注释 2 处通过路由名称来打开 SecondPage。

3. 路由间数据传递

页面跳转的时候经常需要传递数据,一般有两种情况,一种是页面跳转数据传递,另一种是页面跳转返回数据,这里分别来进行介绍。

3.1 页面跳转数据传递

一个页面跳转到一个新的页面数据传递的方式主要有以下两种:

  • 通过 Navigator.push () 或者 Navigator.pushNamed () 方法传递数据
  • 通过 Widget 的构造函数传递数据

一般来说会使用第一种方式,下面来进行举例。

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("第一页"),
      ),
      body: Center(
        child: RaisedButton(
          child: Text("跳转到第二页"),
          onPressed: () {
            Navigator.pushNamed(context, '/Second',arguments: CustomArgumnets('Android进阶之光'));
          },
        ),
      ),
    );
  }
}
class CustomArgumnets {
  String content;
  PassArgumnets(this.content);
}

我们通过 arguments 属性来传递参数,这里自定义了一个 CustomArgumnets,用来传递参数。
改写第一小节 SecondPage 的代码用来获取数据,如下所示。

class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final CustomArgumnets customArgumnets =ModalRoute.of(context).settings.arguments;
    return Scaffold(
      appBar: AppBar(
        title: Text("第二页"),
      ),
      body: Center(
        child: Column(
          children: <Widget>[
            Text('第一页的数据为:'),
            Text(customArgumnets.content),
            RaisedButton(
              onPressed: () {
                Navigator.pop(context);//1
              },
              child: Text('返回第一页'),
            ),
          ],
        ),
      ),
    );
  }
}

运行代码,跳转到第二页,效果如下所示。

Zc1Z4I.png

3.2 页面跳转返回数据

除了页面跳转需要传递数据,有时还需要从第二个页面返回数据,改写 3.1 小节的 SecondPage 注释 1 处的代码。

Navigator.pop(context,CustomArgumnets('Android进阶解密'));

接着改写 FirstPage,如下所示。

class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("第一页"),
      ),
      body: Center(
        child: RaisedButton(
          child: Text("跳转到第二页"),
          onPressed: () {
            _navigateToSecondPage(context);
          },
        ),
      ),
    );
  }
  _navigateToSecondPage(BuildContext context) async {
    dynamic customArgumnets = await Navigator.pushNamed(context, '/Second',
        arguments: CustomArgumnets('Android进阶之光'));//1
    print(customArgumnets.content);
  }
}

注释 1 处的代码可以接 java 收返回的结果,并且使用异步来防止阻塞 UI。最后贴上完整的代码。

import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "Flutter",
      initialRoute: '/First',
      routes: {
        '/First': (context) => FirstPage(),
        "/Second": (context) => SecondPage()
      },
      home: FirstPage(),
    );
  }
}
class FirstPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("第一页"),
      ),
      body: Center(
        child: RaisedButton(
          child: Text("跳转到第二页"),
          onPressed: () {
            _navigateToSecondPage(context);
          },
        ),
      ),
    );
  }
  _navigateToSecondPage(BuildContext context) async {
    dynamic customArgumnets = await Navigator.pushNamed(context, '/Second',
        arguments: CustomArgumnets('Android进阶之光'));
    print(customArgumnets.content);
  }
}
class SecondPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final CustomArgumnets customArgumnets =ModalRoute.of(context).settings.arguments;
    return Scaffold(
      appBar: AppBar(
        title: Text("第二页"),
      ),
      body: Center(
        child: Column(
          children: <Widget>[
            Text('第一页的数据为:'),
            Text(customArgumnets.content),
            RaisedButton(
              onPressed: () {
                Navigator.pop(context,CustomArgumnets('Android进阶解密'));
              },
              child: Text('返回第一页'),
            ),
          ],
        ),
      ),
    );
  }
}
class CustomArgumnets {
  String content;
  CustomArgumnets(this.content);
}

运行程序,当我们点击返回第一页,在控制台中会打印出 Android 进阶解密。

本作品采用 知识共享署名 4.0 国际许可协议 进行许可
标签: flutter
最后更新:2019年9月19日

NiZerin

博主已经躺平了,后面很少会更新博客。

打赏 点赞
< 上一篇
下一篇 >

文章评论

  • ⁹⁴₀₈₂₇

    gg

    2019年11月1日
    回复
  • ⁹⁴₀₈₂₇

    gg

    2019年11月1日
    回复
  • ArMin
    2020年3月6日
    回复
  • razz evil exclaim smile redface biggrin eek confused idea lol mad twisted rolleyes wink cool arrow neutral cry mrgreen drooling persevering
    取消回复

    分类
    • Angular
    • CSS3
    • docker
    • Flutter
    • git
    • Go
    • H5
    • Java
    • JavaScript
    • Laravel
    • linux
    • Node.js
    • PHP
    • Python
    • React
    • redis
    • Vue.js
    • windows
    • WordPress
    • 交流
    • 小程序
    • 工具
    • 网站公告
    标签聚合
    go laravel translations wordpress flutter php javascript vue
    友情链接
    • PHP函数字典
    • 宝塔运维特惠
    • 科学上网
    • 阿里云特惠

    COPYRIGHT © 2021 nizer.in. ALL RIGHTS RESERVED.

    Theme Kratos Made By Seaton Jiang