四、Flutter之组件间通信

这里学了两种通信方式,一种是回调、另一种是借用第三方库event_bus,其他的还有GlobalKey、ValueNotifier、Redux等,后续再研究。

一、回调

组件间通信可以用回调方式,这里不需要像java新建一个接口类再实现,Dart是支持把方法作为对象传递的,也就是说可以直接把需要回调的方法作为变量传给目标。

/**
 * 父子、兄弟组件通信
 */
class WidgetContactDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Material(
        child: new Scaffold(
      appBar: new AppBar(
        title: new Text("组件间通信"),
      ),

      //主体
      body: new ParentWidget(),
    ));
  }
}

//父组件
class ParentWidget extends StatefulWidget {
  @override
  State createState() {
    return _ParentWidget();
  }
}

class _ParentWidget extends State {
  var bgColor; //父组件背景色
  var btnColor; //子组件背景色

  changeParentColor(color) {
    setState(() {
      bgColor = color;
    });
  }

  changeButtonColor() {
    setState(() {
      btnColor = RandomColor().get();
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: MediaQuery.of(context).size.width,
      color: bgColor,
      child: Column(
        children: [
          RaisedButton(
            onPressed: changeButtonColor,
            child: Text('Button1,点击修改button2背景色'),
          ),
          //这里把方法changeParentColor和变量btnColor传入MyButton,如果changeParentColor是无参函数,可以直接用MyButton(changeParentColor,btnColor),
          MyButton((c) => changeParentColor(c), btnColor),
        ],
      ),
    );
  }
}

//子组件按钮,需要传入一个点击事件callback和一个背景色btnColor,点击时会调用callback,而btnColor在外部修改的时候,子组件也会响应修改。
class MyButton extends StatefulWidget {
  Function callback;
  var btnColor;

  //dart构造函数,可以直接把传入参数赋值给相应变量
  MyButton(this.callback, this.btnColor);

  //下面这种写法的构造函数支持MyButton(callback:(c)=>changeParentColor(c),btnColor:btnColor),
//  MyButton({Key key,this.callback,this.btnColor}) : super(key:key) ;

  @override
  State createState() {
    return _MyButton();
  }
}

class _MyButton extends State {
  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      //State里可以通过widget访问其StatefulWidget里的变量,此处常见错误!不能写作widget.callback(Colors.black12)
      onPressed: () => widget.callback(RandomColor().get()),
      child: Text('Button2,点击修改父控件背景色'),
      color: widget.btnColor,
    );
  }
}

//随机颜色类
class RandomColor {
  final bgColors = [
    Colors.white,
    Colors.yellow,
    Colors.orange,
    Colors.cyan,
    Colors.lime,
    Colors.pinkAccent
  ];

  Color get() {
    return bgColors[Random.secure().nextInt(bgColors.length)];
  }
}

这段代码实现了点击button1修改button2的颜色,点击button2修改parent的颜色,代码中的new关键字都省略了,这是dart2中的新特性。
从外部修改button2的颜色比较简单,只要在button1点击事件中修改传入button2的变量btnColor即可;
从button2点击修改父组件颜色,就需要用到回调,父控件构建button2的时候传入回调函数MyButton((c) => changeParentColor(c), btnColor),这里changeParentColor是作为一个对象之间传入子控件赋值给callback的,而子控件在onPressed: () => widget.callback(RandomColor().get()),这里设置了点击事件,点击时调用widget.callback即changeParentColor,以达到从内部向外部通信的目的,注意不能写成onPressed:widget.callback(RandomColor().get())

二、eventbus

先在pubspec.yaml里增加依赖

dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.2
  event_bus: ^1.0.1//增加依赖

dart文件中再导入包

import 'package:event_bus/event_bus.dart';

接下来就可以使用eventbus进行通信了,下面代码实现了点击button3可以修改button4的颜色,也就是点击的时发送一个事件,button4监听到该事件就改变自身颜色。

/**
 * 以下是用eventbus进行通信
 */

EventBus eventBus = new EventBus();

//新建修改颜色的事件
class ColorEvent{
  Color color;
  ColorEvent(this.color);
}

//button3
class MyButton3 extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      //点击的时候发送改变颜色事件
      onPressed: () => eventBus.fire(ColorEvent(RandomColor().get())),
      child: Text('Button3,点击修改Button4颜色'),
    );
  }
}

//button4
class MyButton4 extends StatefulWidget {

  @override
  State createState() {
    return _MyButton4();
  }
}

class _MyButton4 extends State {
  Color bgColor;

  @override
  void initState() {
    //注册eventBus事件,监听到变化的时候调用changeColor(color)
    eventBus.on().listen((ColorEvent data) => changeColor(data.color));
    super.initState();
  }

  changeColor(color){
    //若不对mounted进行判断,会报错 setState() called after dispose()
    if(mounted){
      setState(() {
        bgColor=color;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return RaisedButton(
      onPressed: ()=>{},//必须给onPressed一个空方法,不能是null,否则无法修改color属性
      child: Text('Button4'),
      color: bgColor,
    );
  }
}

eventbus的Git地址:https://github.com/marcojakob/dart-event-bus
详解可参考:https://cloud.tencent.com/developer/article/1338289

你可能感兴趣的:(四、Flutter之组件间通信)