Flutter 中的页面跳转及页面之间传参(路由跳转)


大多数应用程序具有多个页面或视图,并且希望将用户从页面平滑过渡到另一个页面。Flutter 的路由和导航功能可帮助你管理应用中屏幕之间的命名和过渡。

管理多个页面时有两个核心概念和类:Route 和 Navigator。 一个 Route 是一个屏幕或页面的抽象,Navigator 是管理 Route 的 Widget。Navigator 可以通过使 Route 入栈和出栈来实现页面之间的跳转。

在 Android 开发中,Activity 相当于“路由”,在 iOS 开发中,ViewController 相当于“路由”。在 Flutter 中,“路由”也是一个 widget。

注:在 Flutter 中,屏 (screen) 和 页面 (page) 都叫做路由 (route)。

用 Navigator.push() 跳转到第二个路由

使用 Navigator.push() 方法跳转到新的路由, push() 方法会添加一个 Route 对象到导航器的堆栈上。那么这个 Route 对象是从哪里来的呢?你可以自己实现一个,或者直接使用 MaterialPageRoute 类。使用 MaterialPageRoute 是非常方便的,框架已经为我们实现了和平台原生类似的切换动画。

onPressed: () {
  Navigator.push(
    context,
    MaterialPageRoute(builder: (context) => SecondRoute()),
  );
}

用 Navigator.pop() 回退到第一个路由

现在,我们想结束掉第二个路由,返回到第一个路由,应该如何操作呢?

其实非常简单,直接调用 Navigator.pop() 即可。使用 Navigator.pop() 方法, pop() 方法会从导航器堆栈上移除 Route 对象。

示例,在第二个路由页面 SecondRoute 中,点击按钮,退回到上一个路由页面:

onPressed: () {
  Navigator.pop(context);
}

跳转时传参

假如我们需要在打开新路由时,传递参数给新路由,怎么做呢?

方法就是:

  1. 给新路由的构造函数,添加一个参数。
  2. 在 Navigator.push 的时候,在创建新路由时,将要传递的数据,作为新路由构造函数的参数,传递过去即可。

示例:

这是第一个路由页面,展示一个任务列表,当点击列表中的任务时,进入任务详情(传参过去):

@override
  Widget build(BuildContext context) {
    return ListView.builder(
        itemCount: 10,
        itemBuilder: (context, index) {
          NowListItemVO vo = nowList[index];
          return new Card(
            child: new ListTile(
              title: new Text(vo.title),
              subtitle: new Text(vo.content),
              leading: new Icon(Icons.edit),
              trailing:  new Text((vo.complete * 100 / vo.total).toString() + "%"),
              onTap: () => Navigator.push(context, MaterialPageRoute(builder: (context) => TaskDetailPage(nowListItemVO : vo))),

            ),
          );
        },

    );
  }

任务详情路由:

class TaskDetailPage extends StatelessWidget {
  var nowListItemVO;

  TaskDetailPage({Key key, @required this.nowListItemVO}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("任务详情"),

      ),
      body: Center(
        child: new Card(
            child: new ListTile(
              title: new Text(nowListItemVO.title),
              subtitle: new Text(nowListItemVO.content),
              leading: new Icon(Icons.edit),
              trailing:  new Text((nowListItemVO.complete * 100 / nowListItemVO.total).toString() + "%"),
            ),
        ),
      ),
    );
  }
}