一,概述 

   flutter一个重要的特性就是组件化。组件分为两种状态,一种是StatefulWidget有状态组件,一种是StatelessWidget无状态组件。 无状态组件不能更新状态,有状态组件具有类似刷新的机制,可更改状态。
  功能模块都可以通过继承两种状态组件实现功能模块封装。组件间通信,一般存在一下两种关系。

  • 父子组件通信
  • 兄弟组件通信       

二, 通信实现方式

  • 回调通信
  • 需求“点击子组件,修改父组件的背景颜色与子组件背景颜色一致”
  • 代码实现
//父组件

class ParentWidget extends StatefulWidget {
  final String title;
  ParentWidget({Key key,this.title}):super(key:key);

  @override
  State<StatefulWidget> createState() {
    return new ParentWidgetState();
  }
}

class ParentWidgetState extends State<ParentWidget> {
  Color  containerBg  = Colors.orange;
  //回调函数
  void changeBackgroundColor(Color newColor){
        setState(() {
           containerBg = newColor;//修改状态
        });
  }
  
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(widget.title),
      ),
      body: new Center(
        child: new GestureDetector(
          onTap: (){
              changeBackgroundColor(Colors.orange);
          },
          child: new Container(
            width: 300,
            height: 300,
            color: containerBg,
            alignment: Alignment.center,
            child: new Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: <Widget>[
                new childrenA(childrenACallBack: changeBackgroundColor),
                new childrenB(childrenBCallBack: changeBackgroundColor),
              ],
            ),
          ),
        )
        ),
      );
   }
}

//子组件(组件A)
class childrenA extends StatelessWidget {
  //定义接收父类回调函数的指针
final ValueChanged<Color> childrenACallBack;
  childrenA({Key key,this.childrenACallBack}):super(key:key);
@override
  Widget build(BuildContext context) {
    return new GestureDetector(
      onTap: (){
       //调用回调函数传值
        childrenACallBack(Colors.green);
      },
      child: new Container(
          width: 80,
          height: 80,
          color: Colors.green,
          child: new Text('ChildrenA'),
      ),
    );
  }
}

//子组件(组件B)
class childrenB extends StatelessWidget {
  final ValueChanged<Color> childrenBCallBack;
  childrenB({Key key,this.childrenBCallBack}):super(key:key);
  
 @override
  Widget build(BuildContext context) {
    return new GestureDetector(
      onTap:(){
          childrenBCallBack(Colors.red);
      },
      child: new Container(
        width: 80,
        height: 80,
        color: Colors.red,
        child: new Text('ChildredB'),
      ),
    );
  }
}
  • 功能实现
  • 使用场景:一般用于子组件对父组件传值。
  • InheritedWidget 数据共享
  • 场景:业务开发中经常会碰到这样的情况,多个Widget需要同步同一份全局数据,比如点赞数、评论数、夜间模式等等。
  • 代码实现:
import 'package:flutter/material.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,
        
      ),
      home: new InheritedWidgetTestContainer(),
    );
  }
}

//模型数据
class InheritedTestModel {
  final int count;
  const InheritedTestModel(this.count);
}

//哨所(自定义InheritedWidget类)
class  InheritedContext extends InheritedWidget {
  //构造函数
  InheritedContext({
    Key key,
    @required this.inheritedTestModel,
    @required this.increment,
    @required this.reduce,
    @required Widget child
  }):super(key:key,child:child);

  //变量
  final InheritedTestModel inheritedTestModel;
  final Function() increment;
  final Function() reduce;
  
  //静态方法
  static InheritedContext of(BuildContext context){
    InheritedContext contexts = context.inheritFromWidgetOfExactType(InheritedContext);
    return context.inheritFromWidgetOfExactType(InheritedContext);
  }
  //是否重建取决于Widget组件是否相同
  @override
  bool updateShouldNotify(InheritedContext oldWidget) {
    return inheritedTestModel != oldWidget.inheritedTestModel;
  }
}

class TestWidgetA extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final inheritedContext = InheritedContext.of(context);
    return new Padding(
      padding: const EdgeInsets.only(left: 10.0,top: 10.0,right: 10.0),
      child: new RaisedButton(
        textColor: Colors.black,
        child: new Text('+'),
        onPressed:inheritedContext.increment
      ),
    );
  }
}

class TestWidgetB extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
   final inheritedContext = InheritedContext.of(context);
    return new Padding(
      padding: const EdgeInsets.only(left: 10,top: 10,right: 10.0),
      child: new RaisedButton(
        textColor: Colors.black,
        child: new Text('-'),
        onPressed: inheritedContext.reduce
      ),
    );
  }
}

class TestWidgetC extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final inheritedContext = InheritedContext.of(context);
    final inheritedTestModel = inheritedContext.inheritedTestModel;

    return new Padding(
      padding: const EdgeInsets.only(left: 10.0,top: 10.0,right: 10.0),
      child: new RaisedButton(
        textColor: Colors.black,
        child: new Text('${inheritedTestModel.count}'),
        onPressed: (){
          
        },
      ),
    );
  }
}

class InheritedWidgetTestContainer extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return new InheritedWidgetTestContainerState();
  }
}

class InheritedWidgetTestContainerState extends State<InheritedWidgetTestContainer> {

  InheritedTestModel _inheritedTestModel;

  _initData(){
    _inheritedTestModel = new InheritedTestModel(0);
  }

  @override
  void initState() {
    _initData();
    super.initState();
  }

  _incrementCount(){
    setState(() {
      _inheritedTestModel = new InheritedTestModel(_inheritedTestModel.count + 1);
    });
  }

  _reduceCount(){
    setState(() {
      _inheritedTestModel = new InheritedTestModel(_inheritedTestModel.count - 1);
    });
  }

  @override
  Widget build(BuildContext context) {
    return new InheritedContext(
      inheritedTestModel: _inheritedTestModel,
      increment: _incrementCount,
      reduce: _reduceCount,
      child: new Scaffold(
        appBar: new AppBar(
          title: new Text('InheritedWidgetTest'),
        ),
        body: new Center(
          child: new Column(
            children: <Widget>[
              new TestWidgetA(),
              new TestWidgetB(),
              new TestWidgetC(),
            ],
         ),
        )
      ),
    );
  }
}
  • 功能实现
  • 使用场景
    一般用于父组件对子组件的跨组件传值。
  • Global Key通信
    GlobalKey能够跨Widget访问状态。
  • 需求“点击A子组件,修改B子组件的背景颜色为指定的‘蓝色”
  • 代码实现
//父组件
class ParentWidget extends  StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    return new ParentWidgetState();
  }
}

class ParentWidgetState extends State<ParentWidget> {
  @override
  Widget build(BuildContext context) {
  
    return new Scaffold(
      appBar: new AppBar(
        title:  new Text('组件化'),
      ),
      body: new Center(
        child: new Container(
          color: Colors.grey,
          width: 200,
          height: 200,
          child: new Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: <Widget>[
              new SubWidgetA(key: subAkey),
              new SubWidgetB(key: subBkey)
            ],
          ),
        ),
      ),
    );
  }
}


//子组件A

class SubWidgetA extends StatefulWidget {
  SubWidgetA({Key key}):super(key:key);
 @override
  State<StatefulWidget> createState() {
    return new SubWidgetAState();
  }
}

class SubWidgetAState extends State <SubWidgetA> {

   Color _backgroundColors = Colors.red;//红色
   void updateBackGroundColors(Color colos){
     setState(() {
            _backgroundColors = colos;
     });
   }

   @override
   Widget build(BuildContext context) {
    return new GestureDetector(
      onTap: (){
         subBkey.currentState.updateBackGroundColors(Colors.blue);
          setState(() {
            _backgroundColors = Colors.red;
          });
      },
      child: new Container(
      width: 80,
      height: 80,
      color:_backgroundColors,
      alignment: Alignment.center,
      child: new Text('SubWidgetA'),
    ),
    );
  }
}



//子组件B
class SubWidgetB extends StatefulWidget {
  SubWidgetB({Key key}):super(key:key);
   @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return new SubWidgetBState();
  }
}

class SubWidgetBState extends State<SubWidgetB> {
  
   Color _backgroundColors = Colors.green;//绿色
  void updateBackGroundColors(Color colos){
    setState(() {
            _backgroundColors = colos;
    });
  }
 
  @override
  Widget build(BuildContext context) {
    return new GestureDetector(
      onTap: (){
          subAkey.currentState.updateBackGroundColors(Colors.blue);
          setState(() {
            _backgroundColors = Colors.green;
          });

      },
      child: new Container(
      width: 80,
      height: 80,
      color: _backgroundColors,
      alignment: Alignment.center,
      child: new Text('SubWidgetB'),
    ),
    );
  }
}
  • 功能实现
  • 使用场景:一般用于跨组件访问状态
  • ValueNotifier通信 

     ValueNotifier是一个包含单个值的变更通知器,当它的值改变的时候,会通知它的监听。
  1. 定义ValueNotifierData类,继承ValueNotifier
class ValueNotifierData extends ValueNotifier<String> {
  ValueNotifierData(value) : super(value);
}
  1. 定义_WidgetOne,包含一个ValueNotifierData的实例。
class _WidgetOne extends StatefulWidget {
  _WidgetOne({this.data});
  final ValueNotifierData data;
  @override
  _WidgetOneState createState() => _WidgetOneState();
}
  1. _WidgetOneState中给ValueNotifierData实例添加监听。
@override
initState() {
  super.initState();
  widget.data.addListener(_handleValueChanged);
  info = 'Initial mesage: ' + widget.data.value;
}
 
void _handleValueChanged() {
    setState(() {
      info = 'Message changed to: ' + widget.data.value;
    });
  1. ValueNotifierCommunication组件中实例化_WidgetOne,可以通过改变ValueNotifierData实例的value来触发_WidgetOneState的更新。
@override
Widget build(BuildContext context) {
  ValueNotifierData vd = ValueNotifierData('Hello World');
  return Scaffold(
    appBar: AppBar(title: Text('Value Notifier Communication'),),
    body: _WidgetOne(data: vd),
    floatingActionButton: FloatingActionButton(child: Icon(Icons.refresh),onPressed: () {
      vd.value = 'Yes';
    }),
  );
}
  • 第三方插件
      在这里运用event_bus来实现传值,用于组件与组件之间的传值。
  • event_bus 
  • 引入插件
import 'package:event_bus/event_bus.dart';
  • event_bus用法。
  • 新建消息监测类
import 'package:event_bus/event_bus.dart';
  EventBus eventBus = new EventBus();
  class TransEvent{
   String text;
   TransEvent(this.text);
  }
  • 监测类变化
eventBus.on<TransEvent>().listen((TransEvent data) => show(data.text));
void show(String val) {
 setState(() {
  data = val;
 });
}
  • 触发消息变化
eventBus.fire(new TransEvent('$inputText'));
  • 使用场景:这样我们就可以根据这些来实现组件之间的传值。