flutter07 - 路由

开启一个新路由

创建一个TipRoute路由,它接受一个提示文本参数,负责将传入它的文本显示在页面上,另外TipRoute中我们添加一个“返回”按钮,点击后在返回上一个路由的同时会带上一个返回参数

import 'package:flutter/material.dart'; //导包

//应用入口
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '我是标题',
      theme: ThemeData(
        primarySwatch: Colors.blue,//蓝色主题
      ),
      home: MyHomePage(title: '我是HomePager标题名字'),
    );
  }
}

//首页,继承自有状态组件
class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              '点击进行累加~',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.display1,
            ),
            FlatButton(
              child: Text("打开新的路由"),
              textColor: Colors.blue,
              onPressed: (){
                //导航到新的路由
                Navigator.push(context,MaterialPageRoute(builder: (context){
                  return NewRoute();
                }));
              },
            ),
            FlatButton(
              child: Text("打开新的路由2"),
              textColor: Colors.amber,
              onPressed: (){
                //导航到第二个路由
                Navigator.push(context, MaterialPageRoute(builder: (context){
                  return NewRoute2();

                }));
              },
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}

class NewRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.green,
        title: Text("new Route"),
      ),
      body: Center(
        child: Text("This is new Route"),
      ),
    );
  }
}

class NewRoute2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Colors.red,
        title: Text("第二个页面"),
      ),
      body: Center(
        child: Text("第二个页面的内容"),
      ),
    );
  }
}

MaterialPageRoute

  MaterialPageRoute({
    WidgetBuilder builder,
    RouteSettings settings,
    bool maintainState = true,
    bool fullscreenDialog = false,
  })
  • builder 是一个WidgetBuilder类型的回调函数,它的作用是构建路由页面的具体内容,返回值是一个widget。我们通常要实现此回调,返回新路由的实例。
  • settings 包含路由的配置信息,如路由名称、是否初始路由(首页)。
  • maintainState:默认情况下,当入栈一个新路由时,原来的路由仍然会被保存在内存中,如果想在路由没用的时候释放其所占用的所有资源,可以设置maintainState为false。
  • fullscreenDialog表示新的路由页面是否是一个全屏的模态对话框,在iOS中,如果fullscreenDialogtrue,新页面将会从屏幕底部滑入(而不是水平方向)。

Navigator

两个方法:

Future push(BuildContext context, Route route)

将给定的路由入栈(即打开新的页面),返回值是一个Future对象,用以接收新路由出栈(即关闭)时的返回数据。

bool pop(BuildContext context, [ result ])

将给定的路由入栈(即打开新的页面),返回值是一个Future对象,用以接收新路由出栈(即关闭)时的返回数据。

Navigator执行寻找路由顺序是 initialRoute -> onGenerateRoute -> onUnknownRoute

将给定的路由入栈(即打开新的页面),返回值是一个Future对象,用以接收新路由出栈(即关闭)时的返回数据。

Navigator.push(BuildContext context, Route route)等价于Navigator.of(context).push(Route route)

路由传值

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "页面1",
      theme: ThemeData(
        primarySwatch: Colors.red,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text("页面1"),
        ),
        body: GiveRoute(),
      ),
    );
  }
}

class GiveRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: RaisedButton(
        onPressed: () async {
          //打开新页面,并且等待返回结果
          var result = await Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) {
                return TipRoute(
                  text: "我是传递给TipRoute的文本",
                );
              },
            ),
          );
          print("路由的返回数据为$result");
        },
        child: Text("打开提示页面"),
      ),
    );
  }
}

/**
 * 返回数据的
 */
class TipRoute extends StatelessWidget {
  final String text;

  TipRoute({Key key, @required this.text}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("提示信息"),
      ),
      body: Padding(
        padding: EdgeInsets.all(18),
        child: Column(
          children: <Widget>[
            Text(text),
            RaisedButton(
              onPressed: () => Navigator.pop(context, "我是返回值"),
              child: Text("返回"),
            ),
          ],
        ),
      ),
    );
  }
}

通过构造函数传值到第二个Route

第二个Route通过Navigator.pop(context, “我是返回值”),向第一个Route返回传值

第一个Route通过下面这段代码来接受数据

 return Center(
      child: RaisedButton(
        onPressed: () async {
          //打开新页面,并且等待返回结果
          var result = await Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) {
                return TipRoute(
                  text: "我是传递给TipRoute的文本",
                );
              },
            ),
          );
          print("路由的返回数据为$result");
        },
        child: Text("打开提示页面"),
      ),
    );

命名路由

“命名路由”(Named Route)即有名字的路由

路由表

要想使用命名路由,我们必须先提供并注册一个路由表(routing table),这样应用程序才知道哪个名字与哪个路由组件相对应。其实注册路由表就是给路由起名字,路由表的定义如下:

Map<String, WidgetBuilder> routes;

它是一个Map,key为路由的名字,是个字符串;value是个builder回调函数,用于生成相应的路由widget。

根据路由名字在路由表中查找到对应的WidgetBuilder回调函数,然后调用该回调函数生成路由widget并返回。

使用命名路由

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "路由表 - 命名路由",
      theme: ThemeData(
        primarySwatch: Colors.amber,
      ),
      routes: {
        "/": (context) => HomeDemo(title: "主页"), //使用命名路由 注册首页路由
        "new_page1": (context) => PageRoutes1(),
        "new_page2": (context) => PageRoutes2(),
      },
    );
  }
}

class HomeDemo extends StatelessWidget {
  String title;

  HomeDemo({Key key, @required this.title}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("主页"),
      ),
      body: Center(
        child: Column(
          children: <Widget>[
            RaisedButton(
              onPressed: () {
                Navigator.pushNamed(context, "new_page1");
              },
              child: Text("通过命名路由方式跳转到page1"),
            ),
            RaisedButton(
              onPressed: () {
                Navigator.pushNamed(context, "new_page2");
              },
              child: Text("通过命名路由方式跳转到page2"),
            ),
          ],
        ),
      ),
    );
  }
}

class PageRoutes1 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("页面一"),
      ),
    );
  }
}

class PageRoutes2 extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("页面二"),
      ),
    );
  }
}

通过命名路由注册主页

routes: {
  "/": (context) => HomeDemo(title: "主页"), //使用命名路由 注册首页路由
  "new_page1": (context) => PageRoutes1(),
  "new_page2": (context) => PageRoutes2(),
},

命名路由传递参数

import 'package:first_flutter_app/main.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "命名路由传递参数",
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      routes: {
        "/": (context) => HomeDemo(),
        "newpage": (context) => NewPageRoute(),
      },
    );
  }
}

class HomeDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("命名路由传递参数"),
        backgroundColor: Colors.amberAccent,
      ),
      body: Center(
        child: RaisedButton(
          onPressed: () {
            Navigator.of(context).pushNamed("newpage", arguments: "项目ID1234");
          },
          child: Text("命名路由 传递函数"),
        ),
      ),
    );
  }
}

class NewPageRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

    var args = ModalRoute.of(context).settings.arguments;

    return Scaffold(
      appBar: AppBar(
        title: Text("NewPageRoute"),
        backgroundColor: Colors.amberAccent,
      ),
      body: Center(
        child: Text("命名路由接受到的参数:$args"),
      ),
    );
  }
}

有构造和无构造的命名路由

import 'package:first_flutter_app/main.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "命名路由传递参数",
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      routes: {
        "/": (context) => HomeDemo(),
        "newpage": (context) => NewPageRoute(), //无构造的
        "tiproute": (context) =>
            TipRoute(text: ModalRoute.of(context).settings.arguments), //有构造的
      },
    );
  }
}

class HomeDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("命名路由传递参数"),
        backgroundColor: Colors.amberAccent,
      ),
      body: Center(
        child: Column(
          children: <Widget>[
            RaisedButton(
              onPressed: () {
                Navigator.of(context)
                    .pushNamed("newpage", arguments: "项目ID1234");
              },
              child: Text("命名路由无构造的 传递函数"),
            ),
            RaisedButton(
              onPressed: () {
                Navigator.of(context)
                    .pushNamed("tiproute", arguments: "你好,我是flutter命名函数传值");
              },
              child: Text("命名路由有构造的 传递函数"),
            )
          ],
        ),
      ),
    );
  }
}

/**
 * 无构造的
 */
class NewPageRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    var args = ModalRoute.of(context).settings.arguments;//本行是接受参数

    return Scaffold(
      appBar: AppBar(
        title: Text("NewPageRoute"),
        backgroundColor: Colors.amberAccent,
      ),
      body: Center(
        child: Text("命名路由接受到的参数:$args"),
      ),
    );
  }
}

/**
 * 有构造的
 */
class TipRoute extends StatelessWidget {
  final String text; //用来接受传过来的信息

  TipRoute({Key key, @required this.text}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("提示信息"),
      ),
      body: Padding(
        padding: EdgeInsets.all(18),
        child: Column(
          children: <Widget>[
            Text(text),
            RaisedButton(
              onPressed: () => Navigator.pop(context, "我是返回值"),
              child: Text("返回"),
            ),
          ],
        ),
      ),
    );
  }
}

路由生成钩子

通过 onGenerateRoute() 函数提取参数,然后把参数传递给组件

开发一个电商APP,当用户没有登录时可以看店铺、商品等信息,但交易记录、购物车、用户个人信息等页面需要登录后才能看。为了实现上述功能,我们需要在打开每一个路由页前判断用户登录状态!如果每次打开路由前我们都需要去判断一下将会非常麻烦。

MaterialApp有一个onGenerateRoute属性,它在打开命名路由时可能会被调用,

之所以说可能,是因为当调用Navigator.pushNamed(…)打开命名路由时,如果指定的路由名在路由表中已注册,则会调用路由表中的builder函数来生成路由组件;如果路由表中没有注册,才会调用onGenerateRoute来生成路由。

onGenerateRoute回调签名如下:

Route<dynamic> Function(RouteSettings settings)
MaterialApp(
  ... //省略无关代码
  onGenerateRoute:(RouteSettings settings){
      return MaterialPageRoute(builder: (context){
           String routeName = settings.name;
       // 如果访问的路由页需要登录,但当前未登录,则直接返回登录页路由,
       // 引导用户登录;其它情况则正常打开路由。
     }
   );
  }
);
发布了49 篇原创文章 · 获赞 6 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/zlhyy666666/article/details/104887105