zoukankan      html  css  js  c++  java
  • 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);

    是用来返回上一个页面的

     
     

     

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

    发送方式的代码没有改变

     

    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");
     
     

    总结

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

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

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



    作者:饥饿的大灰狼  来源:简书

  • 相关阅读:
    HTTP POST GET 本质区别详解
    本人完成的代码生成器,请多提些建议
    .net实现控件视图状态ViewState
    专门用于微信公众平台的Javascript API导言
    [学习笔记]验证上传文件后缀名类型
    专门用于微信公众平台的Javascript API
    1个月成为HTML5前端工程师
    js中用正则表达式 过滤特殊字符, 校验所有输入域是否含有特殊符号
    SharePoint 2010 根据不同的用户权限显示不同的导航
    (原创)Sharepoint webpart中调用web service报错
  • 原文地址:https://www.cnblogs.com/jiuyi/p/12525151.html
Copyright © 2011-2022 走看看