Flutter 之Router 页面跳转

Flutter 之Router 页面跳转

页面跳转在移动开发中是很常见的事情,在Android中打开另外一个页面主要是用startActivity这个方法,在Flutter中也是提供这种能力,主要的使用方式就是通过Navigator 去打开一个页面

1.跳转到另外一个页面

构建FirstScreen和SecondScreen 页面

import 'package:flutter/material.dart';

class FirstScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("First Screen"),
      ),
      body: Center(
        child: RaisedButton(
          onPressed: () {
            Navigator.push(context, MaterialPageRoute(builder: (context) {
              return SecondScreen();
            }));
          },
          child: Text("next screen"),
        ),
      ),
    );
  }
}

class SecondScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Second Screen"),
      ),
      body: Center(
        child: RaisedButton(
            onPressed: () {
               Navigator.pop(context);
            },
          child: Text("back"),
        ),
      ),
    );
  }
}

这里就是跳转的主要代码

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

push方式详解

static Future<T> push<T extends Object>(BuildContext context, Route<T> route)

第一个参数就是上下问信息,类似Android中的Context,第二个参数就是路由信息,也就是要打开的主要页面是哪个,MaterialPageRoute 就是Route其中的一个子类,用于在Material Desgin 模式下打开页面的

Navigator.pop(context);

是用来返回上一个页面的

first_screen.jpg

second_screen.jpg

2.通过routes路径方式跳转到下一个页面

先定义Routes路由表,实际上就是一个Map结构,key是路径,value就是对应的页面

import 'package:flutter/material.dart';

import 'navigation/navigation_demo.dart';

void main() {
  runApp(MaterialApp(
    initialRoute: "/",
    routes: {
      "/": (context) => FirstScreen(),
      '/second': (context) => SecondScreen(),
    },
  ));
}

routes 就是一个map结构,根目录/对应的页面就是FirstScreen,/second路径对应的页面就是ScendScreen,在FirstScreen中打开SecondScreen的方式我们换一下,要通过Navigator.pushNamed方式打开一个在路由表中已经存在的页面

class FirstScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("First Screen"),
      ),
      body: Center(
        child: RaisedButton(
          onPressed: () {
            Navigator.pushNamed(context, "/second");
//            Navigator.push(context, MaterialPageRoute(builder: (context) {
//              return SecondScreen();
//            }));
          },
          child: Text("next screen"),
        ),
      ),
    );
  }
}

3.传递数据到下一个页面

传递数据到下一个页面也是比较常见的情况,例如说在一个相册应用中,有一个列表页面,单击列表中某一个item,应该跳转到照片的详情页面,其实这种情况就应该把照片的信息传递给另外一个页面

传递的方式有两种:

  • 在构造方法中传递数据
  • 在Route中传递数据给下一个页面

在第一个页面构造要传递的数据

class Photo {
  String title;
  String message;

  Photo({this.title, this.message});
}

class FirstScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("First Screen"),
      ),
      body: Center(
        child: RaisedButton(
          onPressed: () {
            Navigator.pushNamed(context, "/second", arguments: Photo(title: "pass title",message: "pass message"));
//            Navigator.push(context, MaterialPageRoute(builder: (context) {
//              return SecondScreen();
//            }));
          },
          child: Text("next screen"),
        ),
      ),
    );
  }
}

在第二个页面获取数据

class SecondScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final Photo photo=ModalRoute.of(context).settings.arguments;
    return Scaffold(
      appBar: AppBar(
        title: Text("Second Screen ${photo.title}"),
      ),
      body: Center(
        child: RaisedButton(
          onPressed: () {
            Navigator.pop(context);
          },
          child: Text("back ${photo.message}"),
        ),
      ),
    );
  }
}

这种方式有种不太好的地方就是需要在下一个页面通过ModalRoute.of(context).settings.arguments; 方式获取传递的数据,其实Flutter中已经提供了这种方式简便处理方式

import 'package:flutter/material.dart';

import 'navigation/navigation_demo.dart';

void main() {
  runApp(MaterialApp(
    home: FirstScreen(),
    onGenerateRoute: (settings) {
      if (settings.name == ThreeScreen.routeName) {
        final Photo args = settings.arguments;
        return MaterialPageRoute(builder: (context) {
          return ThreeScreen(
            title: args.title,
            message: args.message,
          );
        });
      }
    },
  ));
}

onGenerateRoute 是用来统一拦截传递参数的方法,我们可以在这个地方获取传递的数据,然后在构造页面的时候把参数传递给目标页面,这样在目标页面也就是不用考虑如何解析传递过来的数据了

class ThreeScreen extends StatelessWidget {
  static const routeName = '/extractArguments';

  final String title;
  final String message;

  ThreeScreen({this.title, this.message});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("second"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(title),
            Text(message),
          ],
        ),
      ),
    );
  }
}

在这个页面,数据都是通过构造方法中传递了,减少了在页面获取传递数据的代码

class FirstScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("First Screen"),
      ),
      body: Center(
        child: RaisedButton(
          onPressed: () {
            Navigator.pushNamed(context, ThreeScreen.routeName,
                arguments: Photo(title: "args title", message: "args message"));
          },
          child: Text("next screen"),
        ),
      ),
    );
  }
}

发送方式的代码没有改变

three_screen.jpg

4.接收页面返回值

有的时候我们希望在前一个页面接收另外一个页面的数据,这个怎么处理呢

class FirstScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("First Screen"),
      ),
      body: FirstButton(),
    );
  }
}

class FirstButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: RaisedButton(
        onPressed: () {
          Navigator.pushNamed(context, "/second",
                  arguments:
                      Photo(title: "pass title", message: "pass message"))
              .then((vale) {
            final snackBar = SnackBar(
              content: Text('Yay! A SnackBar!'),
              action: SnackBarAction(
                label: 'Undo',
                onPressed: () {
                },
              ),
            );
            Scaffold.of(context).showSnackBar(snackBar);

          });
        },
        child: Text("next screen"),
      ),
    );
  }
}

关键的代码是这段,then 方法用来处理接收数据后的处理逻辑,这个例子中主要通过SnackBar 展示一下接收的信息

Navigator.pushNamed(context, "/second",
        arguments:
            Photo(title: "pass title", message: "pass message"))
    .then((vale) {
  final snackBar = SnackBar(
    content: Text('Yay! A SnackBar!'),
    action: SnackBarAction(
      label: 'Undo',
      onPressed: () {
      },
    ),
  );
  Scaffold.of(context).showSnackBar(snackBar);
});

为什么要单独抽取出FirstButton组件?

是因为SnackBar只能在Scaffold 组件代码中使用会报错

下面代码是用于在推出当前页面的时候,处理了ok 给前一个页面

Navigator.pop(context, "ok");
back_screen.jpg

总结

使用上跟Android 的使用方式类似,有点经验的人掌握这个不是很难

https://docs.flutter.io/flutter/widgets/Navigator-class.html

https://www.raywenderlich.com/110-flutter-navigation-tutorial

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,752评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,100评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,244评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,099评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,210评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,307评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,346评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,133评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,546评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,849评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,019评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,702评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,331评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,030评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,260评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,871评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,898评论 2 351

推荐阅读更多精彩内容