本文章最终实现的效果如下:
本效果在应用开发中常用于 APP 的开屏广告倒计时页面功能。
首先创建一个 单订阅流控制器 StreamController,通过 WidgetsBinding 来监听 Widget 绘制完成后开启一个 Timer 计时器,代码如下:
///通过流 Stream 实现的倒计时功能///倒计时class TestTimeProgressIndicatorPage extends StatefulWidget { @override State createState() { return _TestABPageState(); }}
class _TestABPageState extends State { ///单订阅流 StreamController _streamController = StreamController(); ///计时器 Timer _timer; ///倒计时6秒 double totalTimeNumber = 6000; ///当前的时间 double currentTimeNumber = 6000; @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((timeStamp) { ///当前页面绘制完第一帧后回调 ///在这里开启定时器 startTimer(); }); } ... ...}
Timer 计时器一旦执行了 cancel 方法后,就不可以再次重新覆用,所以在这里封装成了一个方法块,以便多次使用,创建 Timer 计时器的代码如下:
void startTimer() { ///间隔100毫秒执行时间 _timer = Timer.periodic(Duration(milliseconds: 100), (timer) { ///间隔100毫秒执行一次 每次减100 currentTimeNumber -= 100; ///如果计完成取消定时 if (currentTimeNumber <= 0) { _timer.cancel(); currentTimeNumber = 0; } ///流数据更新 _streamController.add(currentTimeNumber); }); }
对于页面的主体结构还是使用了 Scaffold 脚手架组件来构建的,代码如下:
@override Widget build(BuildContext context) { ///页面主体脚手架 return Scaffold( appBar: AppBar( title: Text("测试Stream "), ), body: Column( children: [ ///圆圈部分 Container( child: buildStreamBuilder(), margin: EdgeInsets.only(top: 20, left: 20), ), ///间隔 SizedBox( height: 40, ), ///Demo的控制按钮 OutlineButton( child: Text('开始倒计时'), onPressed: () { currentTimeNumber = totalTimeNumber; if (!_timer.isActive) { startTimer(); } }, ) ], ), ); }
在这里通过 StreamBuilder 实时来刷新进度与文字显示的,代码如下:
/// 监听Stream,每次值改变的时候,更新Text中的内容 StreamBuilder buildStreamBuilder() { return StreamBuilder( ///绑定stream stream: _streamController.stream, ///默认的数据 initialData: 0, ///构建绑定数据的UI builder: (BuildContext context, AsyncSnapshot snapshot) { return Stack( ///子Widget 居中对齐 alignment: Alignment.center, children: [ ///中间显示的文本 Text( (snapshot.data / 1000).toStringAsFixed(0), style: TextStyle(fontSize: 22, color: Colors.blue), ), ///圆圈进度 CircularProgressIndicator( value: 1.0 - snapshot.data / totalTimeNumber,) ], ); }, ); }
运行调试效果如下: