Flutter学习笔记之路由简单实用

路由的简单实用

  • 基本的界面跳转
class FirstScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("first Screen"),
      ),
      body: Center(
        child: RaisedButton(
        child: Text("this is first screen"),
        onPressed: () {
          //go to second screen
          Navigator.push(context, MaterialPageRoute(builder: (context)=>SecodeScreen()));
        },
      )),
    );
  }
}
Screenshot_1545962905.png

如上图所示,第一个界面中包含了一个按钮,在按钮的点击事件中

 Navigator.push(context, MaterialPageRoute(builder: (context)=>SecondScreen()));

这句代码的意思将页面SecondScreen压入路由栈,在Android开发中我们也是同样的使用一个回退栈管理我们的界面,既然有入栈操作,那么一定有出栈了,没错,下面看第二个界面的代码:

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

我们使用了

 Navigator.pop(context);

将该本页面弹出路由栈,从而返回到第一个页面。
以上就是例子可以在官方文档中找到,这只是最简单的路由跳转,但是平时我们开发经常需要在页面之间传值,所以下面我们来看看,flutter中路由如何传递参数。

  • 传递参数到新页面
    我们继续使用官方的例子,首先定义一个实体类,
class Todo{
  final String title;
  final String desc;
  Todo(this.title,this.desc);
}

然后我们创建一个todoList

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: TodoScreen(
          todos: List.generate(10, (i) => Todo("title$i", "Desc$i"))),
    );
  }
}
//列表页
class TodoScreen extends StatelessWidget {
  final List<Todo> todos;
  TodoScreen({Key key, @required this.todos}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("todos"),
      ),
      body: ListView.builder(
        itemCount: todos.length,
        itemBuilder: (context, index) {
          return ListTile(
            title: Text(todos[index].title),
            onTap: () {
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => DetailScreen(todo: todos[index])));
            },
          );
        },
      ),
    );
  }
}

//详情页
class DetailScreen extends StatelessWidget {
  final Todo todo;
  DetailScreen({Key key, @required this.todo}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(todo.title),
      ),
      body: Center(
        child: Text(todo.desc),
      ),
    );
  }
}

在代码里我们通过

      Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => DetailScreen(todo: todos[index])));
            },
          );

将todo传到了详情页,也就是通过构造函数传值,在flutter中一切都是widget,我们在DetailScreen里通过构造函数接收即可。

  • 携带参数返回
    在Android开发中,我们通常使用startActivityForResult启动新页面,这样可以在当前中重写onActivityForResult来接收新页面返回的参数,那么在Flutter中该怎么坐呢,答案是使用Navigator.Pop(),
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        // This is the theme of your application.
        //
        // Try running your application with "flutter run". You'll see the
        // application has a blue toolbar. Then, without quitting the app, try
        // changing the primarySwatch below to Colors.green and then invoke
        // "hot reload" (press "r" in the console where you ran "flutter run",
        // or simply save your changes to "hot reload" in a Flutter IDE).
        // Notice that the counter didn't reset back to zero; the application
        // is not restarted.
        primarySwatch: Colors.blue,
      ),
      home: HomeScreen(),
    );
  }
}

class SelectionButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return RaisedButton(
      child: Text('pick an option,any option'),
      onPressed: () {
          _navigateAndDisplaySelection(context);
      },
    );
  }
}
_navigateAndDisplaySelection(BuildContext context) async{
    final result  = await Navigator.push(context, 
    MaterialPageRoute(builder: (context)=>SelectionScreen())    
    );
    Scaffold.of(context)
    ..removeCurrentSnackBar()
    ..showSnackBar(SnackBar(content:Text("$result")));
}
class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text('home screen'),
      ),
      body: Center(child: SelectionButton()),
    );
  }
}
class SelectionScreen extends StatelessWidget{
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("pick on option"),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Padding(
              padding: const EdgeInsets.all(8.0),
              child: RaisedButton(
                onPressed: (){
                  Navigator.pop(context,"yep");
                },
                child: Text("yep"),
              ),
            ),
              Padding(
              padding: const EdgeInsets.all(8.0),
              child: RaisedButton(
                onPressed: (){
                  Navigator.pop(context,"nope");
                },
                child: Text("nope"),
              ),
            )
          ],
        ),
      ),
    );
  }

}

Pop方法的第二个参数是一个

T result

这样我们在出栈的时候可以将参数带回到上一个页面,在上一个页面中,我们这样来接收

_navigateAndDisplaySelection(BuildContext context) async{
    final result  = await Navigator.push(context, 
    MaterialPageRoute(builder: (context)=>SelectionScreen())    
    );
    Scaffold.of(context)
    ..removeCurrentSnackBar()
    ..showSnackBar(SnackBar(content:Text("$result")));
}
  • 命名路由
    首先我们先定义一个路由映射关系
class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
  
        primarySwatch: Colors.blue,
      ),
      home: FirstScreen(),
      routes: {
        '/second':(context)=>SecondScreen()
      },
    );
  }
}

routes是一个map,用来管理我们定义的命名路由,之后我们就可以使用

  Navigator.pushNamed(context, "/second");

来进行路由的跳转,但是命名路由的方式有一个缺点,就是不能直接携带参数,只能静态的在注册路由的时候这么写:

 routes: {
        '/second':(context)=>SecondScreen('params')
      },

这样在传递一些动态的改变的参数时候就显得不方便。

  • Hero控件
    这个很像Android里的共享元素,比如页面A和页面B都有一张相同的图片,让他们之间跳转的时候,图片无缝过渡,在Flutter使用Hero可以实现这一效果。下面来看看代码中如何实现。
class HeroApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Transition Demo',
      home: MainScreen(),
    );
  }
}

class MainScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Main Screen'),
      ),
      body: GestureDetector(
        child: Hero(
          tag: 'imageHero',
          child: Image.network(
            'https://raw.githubusercontent.com/flutter/website/master/src/_includes/code/layout/lakes/images/lake.jpg',
          ),
        ),
        onTap: () {
          Navigator.push(context, MaterialPageRoute(builder: (_) {
            return DetailScreen();
          }));
        },
      ),
    );
  }
}

class DetailScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: GestureDetector(
        child: Center(
          child: Hero(
            tag: 'imageHero',
            child: Image.network(
              'https://raw.githubusercontent.com/flutter/website/master/src/_includes/code/layout/lakes/images/lake.jpg',
            ),
          ),
        ),
        onTap: () {
          Navigator.pop(context);
        },
      ),
    );
  }
}

在不同页面通过给Hero设置相同的tag,使它们关联起来。

总结

Flutter中路由的常用使用方式基本介绍完了,主要参考官方例子,如有不足,欢迎指正。

参考

Flutte Doc

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

推荐阅读更多精彩内容