美文网首页FlutterFlutter
Flutter Navigation(导航)

Flutter Navigation(导航)

作者: iwakevin | 来源:发表于2018-12-06 16:05 被阅读103次

    在 Flutter 里实现页面的导航需要使用两个类:NavigatorRoute。Navigator 负责页面的栈结构处理,Route 复杂页面的路径处理。

    在 Flutter 里导航器使用栈的结构管理页面,当需要添加一个页面时,使用入栈的方式。当需要退出一个页面时,使用出栈的方式。也可以不入栈而是直接替换当前页面。

    路由表

    移动应用程序通常管理大量的路由,通过名称来引用它们通常是最容易的。

    简单的做法是在 runApp 里,就定义好所有的路由,这样可以做集中式管理,也是非常建议的做法。

    一个 MaterialApp 是最简单的设置方式,MaterialApp 的 home 成为导航器堆栈底部的路由。要在堆栈上推送(push)一个新路由,可以创建一个具有构建器功能的MaterialPageRoute 实例。

    void main() {
        runApp(new MaterialApp(
            home: new MyAppHome(),
            // 路由
            routes: <String, WidgetBuilder> {
                '/a': (BuildContext context) => new MyPage(title: 'page A'),
                '/b': (BuildContext context) => new MyPage(title: 'page B'),
                '/c': (BuildContext context) => new MyPage(title: 'page C'),
            },
        ));
    }
    

    当需要路由切换的时候,可以这样处理。

    Navigator.pushNamed(context, '/b');
    

    传递数据

    很多时候在切换路由时需要传递一些数据,比如 id 之类的,那么应该怎么做?

    在使用动态路由时,可以通过闭包环境来传递数据。

    String id = 'abc';                                              // <--- id
    
    Navigator.push(context, new MaterialPageRoute<void> (
        // 新的页面
        builder: (BuildContext context) {
            return new Scaffold(
                body: new Center(
                    child: new FlatButton(
                        child: new Text('POP'),
                        onPressed: () {
                            print(this.id);                         // <--- id
                            Navigator.pop(context);
                        },
                    ),
                ),
            );
        },
    ));
    

    在使用路由表的时候,只能提供全局变量来传递信息。

    var id = 'abc';
    
    void main() {
        runApp(new MaterialApp(
            home: new MyAppHome(),
            // 路由
            routes: <String, WidgetBuilder> {
                '/a': (BuildContext context) => new MyPage(id: id),
            },
        ));
    }
    

    入栈一个页面

    当需要入栈一个页面时,使用 Navigator.push 函数,这个函数接受一个上下文和新的页面结构。第二个参数是一个路由器 MaterialPageRoute

    // 在某个点击事件里
    Navigator.push(context, new MaterialPageRoute<void> (
        // 新的页面
        builder: (BuildContext context) {
            return new Scaffold(
                appBar: new AppBar(title: new Text('My Page')),
                body: new Center(
                    child: new FlatButton(
                        child: new Text('POP'),
                        onPressed: () {
                            Navigator.pop(context);
                        },
                    ),
                ),
            );
        },
    ));
    

    出栈一个页面

    当需要出栈一个页面时,使用 Navigator.pop 函数,这个函数接受一个上下文。

    new FlatButton(
        child: new Text('POP'),
        onPressed: () {
            Navigator.pop(context);
        },
    ),
    

    接受返回值

    实际上 pushNamed 是一个异步函数,它返回一个 Future,在使用 Navigator.pop 的时候,第二个参数就是返回的值。

    Navigator.pop(context, 'abc');
    
    Navigator.pushNamed(context, '/router/second').then((value) {
        print(value);   // --> abc
    });
    

    导航切换动画

    默认的导航切换动画,在 Android 上是一个从底端到顶端的弹出过程,在 iOS 上是一个从右边到左边的平移过程。

    为了统一,可以通过自定义一个路由,包括路由模态屏障的颜色和行为以及路由其他方面的动画转换。

    // 动画效果,要把它放在外面去,并且是 static 的。
    static SlideTransition createTransition(Animation<double> animation, Widget child) {
        return new SlideTransition(
            // 从右到左
            position: new Tween<Offset>(
                begin: const Offset(1.0, 0.0),
                end: const Offset(0.0, 0.0),
            ).animate(animation),
            child: child,
        );
    }
    
    Navigator.of(context).push(
        new PageRouteBuilder(
            pageBuilder: (
                BuildContext context,
                Animation<double> animation,
                Animation<double> secondaryAnimation,
            ) {
            // 目标页
            return new PageView();
        },
        transitionsBuilder: (               // --> 固定写法
            BuildContext context,
            Animation<double> animation,
            Animation<double> secondaryAnimation,
            Widget child,
        ) => HomePageState.SlideTransition(animation, child),
    ));
    

    实际上,默认在 Android 上的效果是:

    // 从下到上
    position: new Tween<Offset>(
        begin: const Offset(0.0, 1.0), // (x, y)
        end: const Offset(0.0, 0.0),
    ).animate(animation),
    

    这里只是把 x 与 y 对换就变成了平移。

    得出几个不同的方向动画。

    // 从上到下
    position: new Tween<Offset>(
        begin: const Offset(0.0, -1.0), // (x, y)
        end: const Offset(0.0, 0.0),
    ).animate(animation),
    
    // 从左到右
    position: new Tween<Offset>(
        begin: const Offset(-1.0, 0.0), // (x, y)
        end: const Offset(0.0, 0.0),
    ).animate(animation),
    

    神奇的是 begin 可以使用对角移动的方式,也就是 (1.0, 1.0)、(-1.0, -1.0)

    除了平移之外,还可以定义一些旋转的动画。

    static FadeTransition createFadeTransition(Animation<double> animation, Widget child) {
        return new FadeTransition(
            opacity: animation,
            child: new RotationTransition(
                turns: new Tween<double>(
                    begin: 0.8,
                    end: 1.0
                ).animate(animation),
                child: child,
            ),
        );
    }
    

    当 begin 与 end 都为 1.0 时,FadeTransition 是一个透明渐变过程。

    相关文章

      网友评论

        本文标题:Flutter Navigation(导航)

        本文链接:https://www.haomeiwen.com/subject/jlpocqtx.html