一,概述
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是一个包含单个值的变更通知器,当它的值改变的时候,会通知它的监听。
- 定义ValueNotifierData类,继承ValueNotifier
class ValueNotifierData extends ValueNotifier<String> { ValueNotifierData(value) : super(value); }
- 定义
_WidgetOne
,包含一个ValueNotifierData的实例。class _WidgetOne extends StatefulWidget { _WidgetOne({this.data}); final ValueNotifierData data; @override _WidgetOneState createState() => _WidgetOneState(); }
_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; });
- 在
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'; }), ); }
- 定义ValueNotifierData类,继承ValueNotifier
- 第三方插件
在这里运用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'));
-
- 使用场景:这样我们就可以根据这些来实现组件之间的传值。
- 引入插件
- event_bus
来源:oschina
链接:https://my.oschina.net/u/4278828/blog/4767407