美文网首页
Flutter路由实践

Flutter路由实践

作者: 勇往直前888 | 来源:发表于2019-08-09 18:39 被阅读0次

基本路由

navigator.push 的定义如下:

  @optionalTypeArgs
  static Future<T> push<T extends Object>(BuildContext context, Route<T> route) {
    return Navigator.of(context).push(route);
  }

可以看出,方法接收两个参数,一个是上下文context,基本原样给,不用深究。另外一个是 Route Widget,但是 Route 是一个抽象类,因此在实际使用中,我们不会直接传入Route,而是会使用MaterialPageRoute

 MaterialPageRoute({
    @required this.builder,
    RouteSettings settings,
    this.maintainState = true,
    bool fullscreenDialog = false,
  })

核心是提供一个builder函数,比如像下面这样:

    // 跳转到Page2页面
    Navigator.push(
      context,
      MaterialPageRoute(builder: (context) => Page2()),
    );

navigator.pop 的定义如下:

  @optionalTypeArgs
  static bool pop<T extends Object>(BuildContext context, [ T result ]) {
    return Navigator.of(context).pop<T>(result);
  }

使用的例子:

onPressed: () {
   Navigator.pop(context);
},

点击导航栏的返回图标,这个函数就会被默认执行,不需要自己写。

传值

MaterialPageRoute 的构造参数中的 RouteSettings: settings 这个参数就是路由的基本信息,它的arguments 可以用来存储路由相关的参数字段。

    const RouteSettings({
    this.name,
    this.isInitialRoute = false,
    this.arguments,
  });

下面是一个使用的例子

Navigator.of(context).push(
  new MaterialPageRoute(
    builder: (context) {
      return NewRouteWidget();
    },
    settings: RouteSettings(
      arguments: {'name': 'postbird'},
    ), // 传参
    fullscreenDialog: true,
  ),
);

目标页面,可以通过ModalRoute获得传过来的参数:

  /// Creates a route that blocks interaction with previous routes.
  ModalRoute({
    RouteSettings settings,
  }) : super(settings: settings);

一个例子如下:

// 新路由页面
class NewRouteWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    Map args = ModalRoute.of(context).settings.arguments;
    return Scaffold(
        appBar: AppBar(title: Text('获取参数')),
        body: Center(
            child: Column(
          children: <Widget>[
            // 这里会显示传递过来的参数:{'name': 'postbird'}
            Text(args.toString()),
          ],
        )));
  }
}

回传参数

navigator.push的返回值是一个Future,所以可以使用async/await得到返回值。

              onPressed: () async {
                try {
                  final value = await Navigator.of(context).pushNamed('/page2');
                  print("收到回传的数据:$value");
                } catch (e) {
                  print("异常:$e");
                }
              },

navigator.pop可以带参数。比如:

                onPressed: (){
                  Navigator.of(context).pop("这是回传的数据");
                }

命名路由

  • 提供一个路由表,这是一个Map,是字符串和WidgetBuilder的对应关系。比如:
/// 路由表
final Map<String, WidgetBuilder> routeTable = {
  '/' : (content) => Home(),
  '/page1' : (content) => Page1(),
  '/page2' : (content) => Page2(),
  '/page3' : (content) => Page3(),
};
  • 把这个路由表放在MaterialApproutes参数中
void main() => runApp(MyApp());

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,
      ),
      routes: routeTable,
    );
  }
}

使用的例子如下,比如跳转到Page1页面:

              onPressed: (){
                Navigator.of(context).pushNamed('/page1');
              }

小结

  • 命名路由使用起来比较简单,只要通过字符串来区分不同的页面就可以了,所有的WidgetBuilder都集中在一个地方。

  • 命名路由的起点页面不需要导入目标页面,不需要知道目标页面的WidgetBuilder。只需要知道路由表中的“名字”就可以了,实现了解耦。

  • 命名路由不能向目标页面传递参数,这个很不方便。基本路由虽然有耦合,使用也相对麻烦,不过可以传递参数。

  • 命名路由和基本路由都可以拿到回传的值,方法是一样的。pushName也是调用push实现的,两种都返回一个Future,使用异步的方式就可以拿到返回值。

  @optionalTypeArgs
  Future<T> pushNamed<T extends Object>(
    String routeName, {
    Object arguments,
  }) {
    return push<T>(_routeNamed<T>(routeName, arguments: arguments));
  }

onGenerateRoute 路由拦截

能否把命名路由和组合路由的优点结合起来呢。方法就是在MaterialApponGenerateRoute参数中提供一个Route的动态生成函数。

import 'package:flutter/material.dart';

import './page/home.dart';
import './page/page1.dart';
import './page/page2.dart';
import './page/page3.dart';

/// 路由表
final Map<String, WidgetBuilder> routeTable = {
  '/' : (content) => Home(),
  '/page1' : (content) => Page1(),
  '/page2' : (content) => Page2(),
  '/page3' : (content) => Page3(),
};

// 动态生成路由
final onGenerateRoute = (RouteSettings settings) {
  // 从路由表得到builder
  final name = settings.name;
  var builder = routeTable[name];

  // 如果路由表中未定义,跳转到未定义路由页面
  if (builder == null) {
    builder = (content) => NotFoundPage();
  }

  // 构建动态的route
  final route = MaterialPageRoute(
    builder: builder,
    settings: settings,
  );

  return route;
};
  • route.dart
  • MaterialPageRoute需要的WidgetBuilder来自路由表
  • MaterialPageRoute的参数来自调用者。
  • 这个形式上是命名路由,但是本质上却是基本路由(也叫动态路由),所以能够传递参数。因此,MaterialApproutes参数不能提供(否则就是命名路由,不能传参),而是提供onGenerateRoute参数。
import 'package:flutter/material.dart';

import './route.dart';

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

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

main.dart

  • 使用的方式和命名路由一样。
Navigator.of(context).pushNamed('/page1');

不传参数,适合大多数情况

Navigator.of(context).pushNamed('/page3', arguments: {
  "title": "透传title",
  "name": 'postbird',
  'password': '123456'
});

传递参数,有些时候需要

  • 获取参数的方法仍然使用ModalRoute.of(context).settings.arguments这是Flutter内部提供的机制,直接用就行。
import 'package:flutter/material.dart';

class Page3 extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    final arguments = ModalRoute.of(context).settings.arguments;
    return Scaffold(
      appBar:AppBar(
        title: Text("页面3"),
      ) ,
      body: Center(
          child : Text("页面3内容区域${arguments != null ? arguments : ''}"),
      ) ,
    );
  }
}

Demo路径

Flutter路由

参考文章

flutter小记之路由和导航
Flutter进阶:路由、路由栈详解及案例分析
flutter中的命名路由
Flutter 路由导航、路由传值、ModalRoute
Flutter 命名路由、路由组、路由替换、路由销毁

相关文章

网友评论

      本文标题:Flutter路由实践

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