写点什么

模拟红绿灯来看 GetX 的定向刷新

作者:岛上码农
  • 2022 年 6 月 18 日
  • 本文字数:2894 字

    阅读完需:约 9 分钟

模拟红绿灯来看GetX的定向刷新

前言

对于有些场景,我们可能有多个组件共享一份状态数据,但是状态数据改变后可能只需要更新其中的一个或多个组件,而不是依赖状态的全部组件。这个时候我们就可以用到 GetX 的定向更新。GetXupdate 方法中可以提供两个可选参数:


void update([List<Object>? ids, bool condition = true]) {  if (!condition) {    return;  }  if (ids == null) {    refresh();  } else {    for (final id in ids) {      refreshGroup(id);    }  }}
复制代码


  • ids:要更新的 id数组,id可以在 GetBuilder 构建的时候指定,若指定了ids,则之后更新与 ids 中的 id 匹配的组件:


GetBuilder<Controller>(  id: 'text'  init: Controller(), // use it only first time on each controller  builder: (_) => Text(    '${Get.find<Controller>().counter}', //here  ),),
复制代码


  • condition:条件表达式,只有当这个条件为真的时候才会更新组件。


例如下面的代码只会在 counter 小于10的时候更新 idtext 的组件。


update(['text'], counter < 10);
复制代码


接下来我们模拟带倒计时的红绿灯来演示GetX 的定向更新的使用。

业务逻辑

为了分别控制红绿灯,我们需要三个组件,分别是红灯、绿灯和黄灯。



然后是倒计时,我们设置规则如下:


  • 绿灯亮的时长为 20 秒,红灯为 10 秒,黄灯为 3 秒,计时通过定时器完成,每隔 1 秒减 1。

  • 三个红灯共用一个计时器,但根据当前亮的灯的状态来定向更新哪个灯的倒计时时间,同时对于不亮的灯我们不显示倒计时时间(因为共享了倒计时时间,如果显示就会不对)。

  • 使用一个枚举来确定当前亮哪个灯,亮灯的次序为绿灯->黄灯->红灯->绿灯……


业务理顺了,开始撸代码!

红绿灯代码

首先我们构建一个通用的交通灯的组件 TrafficLed,需要四个参数:


  • 灯的颜色:ledColor,控制灯的倒计时数字颜色;

  • 倒计时时间:secondsLeft,倒计时时间;

  • 是否显示倒计时:showSeconds,使用 Offstate 控制是否显示倒计时时间。

  • 灯的大小:ledSize,默认尺寸为 60,用于控制灯的尺寸。


对应代码很简单,这里我们为了好看做了点阴影,使得看起来有点立体感。


class TrafficLed extends StatelessWidget {  final Color ledColor;  final int secondsLeft;  final bool showSeconds;  final double ledSize;  const TrafficLed({    Key? key,    required this.ledColor,    required this.secondsLeft,    required this.showSeconds,    this.ledSize = 60.0,  }) : super(key: key);
@override Widget build(BuildContext context) { return Center( child: Container( alignment: Alignment.center, width: ledSize, height: ledSize, decoration: BoxDecoration( color: Colors.black, borderRadius: BorderRadius.circular(ledSize / 2), boxShadow: [ BoxShadow( color: Color(0xFF505050), offset: Offset(1, -1), blurRadius: 0.2, ) ], ), child: Offstage( child: Text( '$secondsLeft', textAlign: TextAlign.center, style: TextStyle( color: this.ledColor, fontSize: 36, fontWeight: FontWeight.bold, ), ), offstage: !showSeconds, ), ), ); }}
复制代码


接下来是整个灯的组合,这里我们使用横向的红绿灯,然后也用阴影做了一个有立体感的背景。关键代码在每个灯都使用了 GetBuilder 包裹,然后指定了每个灯的 id,这里以绿灯为例:


GetBuilder<TrafficLightController>(  id: 'green',  init: lightController,  builder: (state) => TrafficLed(    ledColor: (state.currentLight == TrafficLight.green        ? Colors.green        : Colors.black),    secondsLeft: state.counter,    showSeconds: state.currentLight == TrafficLight.green,  ),),
复制代码


每个灯对应的逻辑如下:


  • 如果当前状态中显示的灯和自身一致,倒计时的文字颜色就使用灯对应的颜色,即红、黄、绿;否则显示黑色(和背景色一致);

  • 绑定状态对象的倒计时时间;

  • 如果当前状态中显示的灯和自身一致,则显示倒计时,否则不显示。

状态管理代码

状态管理控制器为TrafficLightController,代码如下:


enum TrafficLight { green, red, yellow }
class TrafficLightController extends GetxController { late TrafficLight _currentLight; get currentLight => _currentLight;
int _counter = 0; get counter => _counter;
late Timer _downcountTimer;
@override void onInit() { _counter = 20; _currentLight = TrafficLight.green; super.onInit(); }
@override void onReady() { _downcountTimer = Timer.periodic(Duration(seconds: 1), decreament); super.onReady(); }
void decreament(Timer timer) { _counter--; if (_counter == 0) { switch (_currentLight) { case TrafficLight.green: _currentLight = TrafficLight.yellow; _counter = 3; update(['green', 'yellow']); break; case TrafficLight.yellow: _currentLight = TrafficLight.red; _counter = 10; update(['red', 'yellow']); break; case TrafficLight.red: _currentLight = TrafficLight.green; _counter = 20; update(['red', 'green']); break; } } else { switch (_currentLight) { case TrafficLight.green: update(['green']); break; case TrafficLight.yellow: update(['yellow']); break; case TrafficLight.red: update(['red']); break; } } }
@override void onClose() { _downcountTimer.cancel(); super.onClose(); }}
复制代码


这里使用了三个声明周期函数:


  • onInit:设置倒计时时间为 20 秒,灯状态为绿灯;

  • onReady:启动定时器;

  • onClose:关闭定时器。


核心业务逻辑都在 decreament 这个定时器回调方法里,这里如果倒计时到 0 的时候我们切换灯状态,重置倒计时时间,而且只更新该情况下需要刷新的灯(每次 2 个灯需要更新)。如果倒计时没有到 0,那么我们只需要更新当前亮的灯就可以了。通过这种方式,我们可以定向更新,在共享状态数据的同时还可以减少不必要的刷新。

运行效果

运行效果如下图,源码已提交至:GetX 相关代码


总结

本篇介绍了 GetXGetBuilder使用id参数实现定向刷新的特性。这种情况适用于多个组件共用一个状态对象,但更新条件不同的情况,比如本例的红绿灯。同时,GetxControllerupdate 方法还可以实现条件更新,通过id 加条件组合能够实现更加进货精准的定向刷新。


发布于: 刚刚阅读数: 4
用户头像

岛上码农

关注

用代码连接孤岛,公众号@岛上码农 2022.03.03 加入

从南漂到北,从北漂到南的业余码农

评论

发布
暂无评论
模拟红绿灯来看GetX的定向刷新_flutter_岛上码农_InfoQ写作社区