聊聊Flutter-Flutter中的组件通信与状态改变

| 阅读
版权声明 本文是JakePrim 算法实验室原创文章,如您转载必须以链接形式注明原文地址:" https://jakeprim.cn/2019/03/15/flutter-event-bus/
转载请注明出处! 本文基于 知识共享署名-相同方式共享 4.0 国际许可协议发布

Flutter 中的组件如何通信的呢?做过Android都听说过EventBus,那么Flutter 中同样也有event_bus ,Google还是对Android开发者非常友好的.废话不多说直接进入正题

场景分析

如下图所示,场景:当我点击ListView的item时,我要改变测滑菜单中ListView中的item的字体和icon的颜色,同时要将其他的item字体和icon恢复正常的.比如:当前位置是标签,当我点击’快捷创作’时,将‘标签’的字体颜色和icon置为正常,同时改变‘快捷创作’的字体颜色和icon.

image.png

上述分析的场景,在项目中是很常见的.大家可以想想在Android中或者其他H5是如何实现的呢?常见的思路就是遍历改变颜色等.

接下来来看看我的布局,代码如下:

class ItemDrawerAdapter extends StatefulWidget {
  
  State<StatefulWidget> createState() {
    return _ItemDrawerAdapterState();
  }

  ItemDrawerAdapter(this.drawerItem);

  final DrawerItem drawerItem;
}

上述代码中,我将每个item作为一个自定义的组件

/// 测滑菜单页面
class DrawerPage extends StatefulWidget {
  
  State<StatefulWidget> createState() {
    return _DrawerPageState();
  }
}

上述代码,将测滑菜单页面作为一个自定义的组件,内部是一个ListView


  Widget build(BuildContext context) {
    return Container(
      color: Colors.white,
      child: ListView.builder(
        padding: EdgeInsets.zero, //去掉测滑顶部的灰块
        itemBuilder: (context, index) {
          if (index == 0) return _buildHeader(); //头部
          if (index == _count - 1) return Text('上次更新时间'); //尾部
          return ItemDrawerAdapter(DrawerRes.drawerRes1[index - 1]);
        },
        itemCount: _count,
      ),
    );
  }

当点击其中的一个item时,通过event_bus来通知测滑菜单组件,遍历item的model改变色值,然后通过setState来重新渲染界面,核心代码如下:
item的点击事件,通过setState来改变当前item的model的色值,然后发送时间给测滑菜单列表

onTap: () {
        setState(() {
          widget.drawerItem.textColor = Color(AppColor.themeColor);
          if(AppEvent.event != null){
            //发送事件
            AppEvent.event.fire(widget.drawerItem);
          }
        });
      },

测滑菜单实现代码:在setState中改变model中的色值,渲染listView


  void initState() {
    super.initState();
    _updateItem();
  }

  _updateItem() {
    //更新其他item
    if (AppEvent.event != null) {
      //DrawerItem 只接受DrawerItem 事件
      AppEvent.event.on<DrawerItem>().listen((item) {
        setState(() {
          DrawerRes.drawerRes1.forEach((it) {
            if (it != item) {
              it.textColor = Color(AppColor.mainTextColor);
            }
          });
        });
      });
    }
  }

事件总线通常用于Widget之间状态共享,但关于Widget之间状态共享也有一些专门的Package如redux,这和web框架Vue/React是一致的。通常情况下事件总线是足以满足业务需求的,如果你决定使用redux的话,一定要想清楚业务是否真的有必要用它,防止“化简为繁”、过度设计。下一篇来讲解Flutter中的rudex使用.