zoukankan      html  css  js  c++  java
  • 【Flutter学习】组件通信(父子、兄弟)

    一,概述 

       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( 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( 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( 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,
                   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(
               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(
               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'));
        • 使用场景:这样我们就可以根据这些来实现组件之间的传值。
  • 相关阅读:
    XmlDocument 操作 xml
    流模型 操作 xml
    对DataTable进行分组
    xml文件,xml格式字符串 读写
    Jquery中的checkbox 及radio的问题
    简单爬虫获取网页图片
    页面JS实现按钮点击增加输入框
    Log4j配置文件解读和模板页收藏
    JS异步传递数组Action接受的实现与疑惑
    博客园美化手记——CSS Javascript Html
  • 原文地址:https://www.cnblogs.com/lxlx1798/p/11172246.html
Copyright © 2011-2022 走看看