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



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

  • 相关阅读:
    jQuery EasyUI API 中文文档 可调整尺寸
    jQuery EasyUI API 中文文档 链接按钮(LinkButton)
    jQuery EasyUI API 中文文档 手风琴(Accordion)
    jQuery EasyUI API 中文文档 表单(Form)
    jQuery EasyUI API 中文文档 组合(Combo)
    jQuery EasyUI API 中文文档 布局(Layout)
    jQuery EasyUI API 中文文档 拆分按钮(SplitButton)
    jQuery EasyUI API 中文文档 菜单按钮(MenuButton)
    jQuery EasyUI API 中文文档 搜索框
    jQuery EasyUI API 中文文档 验证框(ValidateBox)
  • 原文地址:https://www.cnblogs.com/jiuyi/p/12525151.html
Copyright © 2011-2022 走看看