Flutter开发的传值(Eventbus)、导航和路由(Navigater,Router)

前端开发的传值也是必须的,比如说跳转传值啊,这些再普通不过,在一切皆widget中Flutter中同样是必须要掌握的知识点

先介绍下Flutter中Eventbus的使用,Eventbus这个词语在Android过来的朋友再熟悉不过了,它用于Android的事件发布-订阅总线,应用程序内各个组件之间进行通信,那么在flutter中也可以这么理解的,下面通过实例介绍它的使用吧。

导入框架

dependencies:
  flutter:
    sdk: flutter
 #event_bus框架
  event_bus:  ^1.1.0

下面直接举个简单的例子吧,通过EventBusTest 2回传id值给EventBusTest


效果图.png

EventBusTest 的源码

import 'dart:async';

import 'package:flutter/material.dart';

import 'eventbus_manager/EventBusManage.dart';
import 'test_eventsbus2.dart';

class EventBusTest extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return EventBusState();
  }
}

class EventBusState extends State<EventBusTest> {
  var id = "";

  BuildContext mContext;
  StreamSubscription _subscription;
  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    //监听传id事件
    _subscription =
        JohwenEvent. eventBus.on<IdEvent>().listen((IdEvent data) => show(data.id));
    _subscription.resume();
  }

//刷新id
  void show(String val) {
    print("接收" + val);
    setState(() {
      id = val;
    });
  }

  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    print("接收${id} ");
    return Scaffold(
      appBar: AppBar(
        title: Text("eventbus接收"),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.start,
        children: <Widget>[
          Builder(builder: (context) {
            return Text("EventBus回传的id: ${id}");
          }),
          RaisedButton(
            onPressed:(){
              Navigator.push(
                  context,
                  MaterialPageRoute(
                      builder: (context) => EventBusTest2()));
            },
            color: Colors.blue[400],
            child: new Text('eventbus发送',
                style: new TextStyle(color: Colors.white)),
          ),
        ],
      ),
    );
  }

  @override
  void dispose() {
    // TODO: implement dispose
    super.dispose();
    _subscription.cancel(); //  一定要取消 避免内存泄露
  }
}

EventBusTest 2源码

import 'package:flutter/material.dart';

import 'eventbus_manager/EventBusManage.dart';

class EventBusTest2 extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return EventBusState2();
  }

}

class EventBusState2  extends State<EventBusTest2>{
  TextEditingController idController = new TextEditingController();
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: AppBar(
        title: Text("eventbus发送"),
      ),
      body:Column(
     children: <Widget>[
       new TextField(
         controller: idController,
         decoration: new InputDecoration(hintText: 'eventbus测试传id'),
       ),
       RaisedButton(
         onPressed: (){
           ///这里开始传值 调用fire方法
           eventBus.fire(IdEvent(idController.text.toString()));
           print("发送"+idController.text.toString());
         },
         color: Colors.blue[400],
         child: new Text('发送消息',
             style: new TextStyle(color: Colors.white)),
       )
     ],
      ) ,
    );
  }
}

初始化eventbus和事件


import 'package:event_bus/event_bus.dart';
//EventBus eventBus = new EventBus();

 

  EventBus eventBus = new EventBus();
 

/// Event 模拟传值 id
class IdEvent {
  String id;

  IdEvent(this.id);
}

这里我们需要注意的主要就几个知识点
1,EventBus其核心是基于Dart Streams(流),在这里定义了StreamSubscription _subscription;相当于订阅者, 所以要取消订阅,防止内存泄漏。如果想详细理解flutter 中Stream流,要详细看下其他篇章。
2,eventBus 的订阅方法fire ,万变不离其中,这里照着例子去做你想做的就行啦。

**Flutter导航,路由,传值的方式 **
1,通过 Navigator.pushNamed 导航。

先定义路由名称


 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      child: MaterialApp(
        title: 'scoped',
        theme: ThemeData.dark(),
        home: TopPage(),
        routes: {
//        'objectRoute': (BuildContext context) => new ObjectPage(title: '数据操作'),
          'refresh': (BuildContext context) => new MainPage(),
          'login': (BuildContext context) => new LoginPage(),
          'objectRoute': (BuildContext context) => new ObjectPage(title: '数据操作'),
//        'indexpage': (BuildContext context) => new IndexPage(),
        },
      ),
    );
  }
}

使用

     Navigator.pushNamed(context, "objectRoute");

2,通过Navigator.push

    Navigator.push(
                       context,
                       MaterialPageRoute(
                           builder: (context) => AddThing()));
                 },

3,返回上一级页面

          Navigator.of(context).pop();

4,命名路由如何进行传值
这里摘自 https://cloud.tencent.com/developer/article/1489372

import 'package:flutter/material.dart';
import 'package:flutter_app_google/pages/SearchPage.dart';
import 'pages/tabs/Tabs.dart';

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

class MyApp extends StatelessWidget {

  //配置命名路由信息
  final routes = {
    //如果需要传参,那么在配置的时候加上{arguments};如果不需要传参,则不用加{arguments}
    "/search": (context, {arguments}) => Searchpage(arguments: arguments,),
  };

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Tabs(),
        //统一处理命名路由
        onGenerateRoute: (RouteSettings settings) {
          final String name = settings.name;
          final Function pageContentBuilder = this.routes[name];
          if (pageContentBuilder != null) {//能寻找到对应的路由
            if (settings.arguments != null) {//页面跳转前有传参
              final Route route = MaterialPageRoute(
                  builder: (context) => pageContentBuilder(context,
                      arguments: settings.arguments));
              return route;
            } else {//页面跳转前没有传参
              final Route route = MaterialPageRoute(
                  builder: (context) => pageContentBuilder(context));
              return route;
            }
          }
        });
  }
}

第二步


import 'package:flutter/material.dart';

class Searchpage extends StatelessWidget {
  final arguments;//用于接收命名路由传递过来的参数值
  const Searchpage({Key key, this.arguments}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(//在最底层采取Scaffold组件
      appBar: AppBar(
        title: Text("搜索页面"),
      ),
      //获取命名路由传递过来的参数值
      body: Text("Search Page!传递过来的参数值是:${arguments != null ? arguments['info'] : '默认值'}"),
      floatingActionButton: FloatingActionButton(
        onPressed: (){
          //返回上一级页面
          Navigator.of(context).pop();
        },
        child: Text("back"),
      ),
    );
  }
}

第三步

 Navigator.pushNamed(context, "/search", arguments: {"info":"777"});

现在我们已经了解了命名路由传值该怎么去操作了,但是此时的代码看起来很乱,如果后期需要管理的命名路由多了,那么如果不做代码分离,而是直接像上面那样写的话,就会造成代码堆积,可读性变差,也不利于后期维护。所以,我们有必要做代码分离,那么该如何去做呢?

第1步,在lib文件夹下新建一个routes文件夹,然后在routes文件夹下新增一个 Routes.dart 文件

第2步 普通路由执行跳转页面的关键代码如下:

//Routes.dart

import 'package:flutter/material.dart';
import 'package:flutter_app_google/pages/SearchPage.dart';

//配置命名路由信息
final routes = {
  //如果需要传参,那么在配置的时候加上{arguments};如果不需要传参,则不用加{arguments}
  "/search": (context, {arguments}) => Searchpage(
        arguments: arguments,
      ),
};

//统一处理命名路由
var onGenerateRoute = (RouteSettings settings) {
  final String name = settings.name;
  final Function pageContentBuilder = routes[name];
  if (pageContentBuilder != null) {
    //能寻找到对应的路由
    if (settings.arguments != null) {
      //页面跳转前有传参
      final Route route = MaterialPageRoute(
          builder: (context) =>
              pageContentBuilder(context, arguments: settings.arguments));
      return route;
    } else {
      //页面跳转前没有传参
      final Route route =
          MaterialPageRoute(builder: (context) => pageContentBuilder(context));
      return route;
    }
  }
};

第3步 在main.dart中引入Routes.dart,并且使用暴露出来的接口

import 'package:flutter/material.dart';
import 'package:flutter_app_google/routes/Routes.dart' as prefix0;
import 'pages/tabs/Tabs.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Tabs(),
        //统一处理命名路由
        onGenerateRoute: prefix0.onGenerateRoute);
  }
}

现在我已经将命名路由的配置代码分离到 Routes.dart 文件中了,这样一分离,main.dart中的代码就简洁多了。其实,我们还可以对main.dart中的代码进一步进行优化,也就是说,我们还可以将 Tabs 这个主页面也通过命名路由进行管理,代码如下:


/Routes.dart
//配置命名路由信息
final routes = {
  //如果需要传参,那么在配置的时候加上{arguments};如果不需要传参,则不用加{arguments}
  "/": (context) => Tabs(),
  "/search": (context, {arguments}) => Searchpage(arguments: arguments),
};


//main.dart
void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        // home: Tabs(),
        initialRoute: "/",//初始化的时候加载的路由
        //统一处理命名路由
        onGenerateRoute: prefix0.onGenerateRoute);
  }
}

最后,我们再来看看有状态的组件如何进行路由传值:

import 'package:flutter/material.dart';

class DetailPage extends StatefulWidget {
  final Map arguments;//1,定义传值参数
  DetailPage({Key key, this.arguments}) : super(key: key);//2,重新写构造函数

  _DetailPageState createState() => _DetailPageState(arguments: arguments);//3,将参数值传递给_DetailPageState
}

class _DetailPageState extends State<DetailPage> {
  Map arguments;//4,定义传值参数
  _DetailPageState({this.arguments});//5,重新写构造函数
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("详情页面")),
      body: Text("hulalaDetail!~${this.arguments["name"]}")//6,获取到传递过来的值
    );
  }
}

好了 这个篇章Flutter开发的传值(Eventbus)、导航和路(Navigater,Router),大体就总结到这里了,有不对的,欢迎指正

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,695评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,569评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,130评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,648评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,655评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,268评论 1 309
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,835评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,740评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,286评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,375评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,505评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,185评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,873评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,357评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,466评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,921评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,515评论 2 359