背景
项目中发送验证码功能几乎成了必备,Flutter中实现倒计时的核心类要用到Timmer, 使用Timer.periodic命名构造方法实现倒计时的监听。
_timer = Timer.periodic(Duration(seconds: _interval), (timer) {}
1、为啥使用provider
普遍的做法就是在每次倒计时的时候,重新restate刷新倒计时显示,这样就会导致不必要的页面渲染以及性能的损耗。Flutter提供了ChangeNotifier,可以通过provider,对发送验证码组件进行监听,当倒计时到结束整个过程时,倒计时按钮的变化完成被监听控制,话不多说,代码呈上~~~
pubspec.yaml中导入provider库
链接:pub.flutter-io.cn/packages/pr…
dependencies:
flutter:
sdk: flutter
provider: ^4.3.2
2、倒计时模型类用于被监听消费,这里处理了倒计时的逻辑
class CountDownTimeModel extends ChangeNotifier {
int _timeTotal; //倒计总时长
int _interval; //倒计单位
int currentTime; //倒计时当前时间
Timer _timer; //倒计器
bool isFirst = true; //第一次未点击过
int get() => currentTime;
bool get isFinish => currentTime == _timeTotal;
bool get isNotClicked => this.isFirst;
CountDownTimeModel(this._timeTotal, this._interval) {
currentTime = this._timeTotal;
}
void startCountDown() {
if (_timer != null) {
_timer.cancel();
_timer = null;
}
isFirst = false;
_timer = Timer.periodic(Duration(seconds: _interval), (timer) {
if (timer.tick == _timeTotal) {
//倒计完当前时间重新等于总时间
currentTime = _timeTotal;
_timer.cancel();
_timer = null;
} else {
currentTime--;
}
//触发监听
notifyListeners();
});
}
void cancelTimer() {
_timer?.cancel();
_timer = null;
}
@override
void dispose() {
_timer?.cancel();
_timer = null;
super.dispose();
}
}
3、使用provider新建消费组件,用于消费需要被监听的模型,这里为了方便,抽取成泛型:
class ConsumeComponent<T extends ChangeNotifier> extends StatefulWidget {
final T model;
final Widget child;
final ValueWidgetBuilder<T> builder;
ConsumeComponent({
Key key,
@required this.model,
@required this.builder,
this.child,
}) : super(key: key);
@override
State<StatefulWidget> createState() => _ConsumeComponentState<T>();
}
class _ConsumeComponentState<T extends ChangeNotifier>
extends State<ConsumeComponent<T>> {
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider<T>.value(
value: widget.model,
child: Consumer<T>(
child: widget.child,
builder: widget.builder,
),
);
}
}
核心的代码基本已经处理完了,剩下的就是调用了
调用
ConsumeComponent<CountDownTimeModel>(
model: CountDownTimeModel(6, 1),
builder: (context, model, _) => InkWell(
onTap: !model.isFinish
? null
: () {
model.startCountDown();
},
child: Text(
model.isNotClicked
? 'Send' //未点击过的初始状态
: model.isFinish
? 'Resend' //倒计时结束
: model.currentTime.toString(),//过程中
style: TextStyle(
color: model.isFinish ? Colors.blue : Colors.grey,
),
),
),
),
基本这样就完成了,这就不需要每次倒计时restate页面去build整个widget。我的理解是将被消费对象添加进消费组件中,当被消费对象中notifyListeners()后会触发消费组件进行消费,也就可以控制被被消费对象的行为了,这有点类似java的订阅监听。 可能有理解错漏的地方,还希望建议指正,多多包涵哈哈。