Flutter状态管理Bloc之定时器示例

Xenia ·
更新时间:2024-09-20
· 1859 次阅读

本文实例为大家分享了Flutter状态管理Bloc之定时器的具体代码,供大家参考,具体内容如下

1. 依赖

dependencies:   flutter_bloc: ^2.1.1   equatable: ^1.0.1   wave: ^0.0.8

2. Ticker

Ticker 用于产生定时器的数据流。

/// 定时器数据源 class Ticker {   /// 定时器数据源   /// @param ticks 时间   Stream<int> tick({int ticks}){       return Stream.periodic(Duration(seconds: 1), (x) => ticks - x - 1).take(ticks);   } }

3. TimerBloc

创建 TimerBloc 用于消费Ticker, 我们需要创建定时器状态,定时器事件两个辅助类。其中定时器的状态有

Ready(准备从指定的持续时间开始倒计时)

Running(从指定持续时间开始递减计数)

Paused(在剩余的持续时间内暂停)

Finished已完成,剩余持续时间为0

import 'package:equatable/equatable.dart'; import 'package:meta/meta.dart'; /// 定时器状态 @immutable abstract class TimerState extends Equatable{   /// 时间   final int duration;   /// 构造方法    const TimerState(this.duration);   @override   List<Object> get props => [this.duration]; } /// 准备状态 class Ready extends TimerState {   const Ready(int duration) : super(duration);   @override   String toString() => 'Ready { duration: $duration }'; } /// 暂停状态 class Paused extends TimerState {   const Paused(int duration) : super(duration);   @override   String toString() => 'Paused { duration: $duration }'; } /// 运行状态 class Running extends TimerState {   const Running(int duration) : super(duration);   @override   String toString() => 'Running { duration: $duration }'; } /// 完成状态 class Finished extends TimerState{   const Finished() : super(0); }

所有的State都继承自抽象类TimerState,因为不论在哪个状态,我们都需要知道剩余时间。

4. TimerEvent

我们需要处理的事件有

Start (通知TimerBloc定时器应该开始)

Pause (通知TimerBloc计时器应该暂停)

Resume(通知TimerBloc应该恢复计时器)

Reset (通知TimerBloc定时器应重置为原始状态)

Tick (通知TimerBloc需要更新剩余时间)

import 'package:equatable/equatable.dart'; import 'package:meta/meta.dart'; /// 定时器事件 @immutable abstract class TimerEvent extends Equatable{   const TimerEvent();   @override   List<Object> get props => []; } /// 开始时间 class Start extends TimerEvent {   /// 定时器时间   final int duration;   const Start({@required this.duration});   @override   String toString() => 'Start { duration: $duration }'; } /// 暂停事件 class Paused extends TimerEvent {} /// 恢复状态 class Resumed extends TimerEvent {} /// 重置状态 class Reset extends TimerEvent {} /// 定时器事件 class Tick extends TimerEvent {   /// 当前时间   final int duration;   const Tick({@required this.duration});   @override   List<Object> get props => [this.duration];   @override   String toString() => 'Tick { duration: $duration }'; }

5. TimerBloc 实现

1.初始化状态Ready(_duration)
2.创建Ticker对象, 用户获取数据流
3.实现mapEventToState方法
4.当event为Start时, 需要开启数据流
5.创建StreamSubscription, 处理流的不同状态, 并在bloc的close方法中关闭它
6.当event为Tick时, 需要处理数据的更新
7.当event为Pause时, 需要停止定时器
8.当event为Resume时, 需要重新启动定时器
9.当event为reset时, 需要重置定时器

import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:flutter/material.dart'; import 'package:state_manage/timer/ticker.dart'; import './bloc.dart'; /// 定时器Bloc class TimerBloc extends Bloc<TimerEvent, TimerState> {   /// 定时器时间   final int _duration = 60;   /// 定时器数据流   final Ticker _ticker;   // 流订阅   StreamSubscription<int> _tickerSubscription;   TimerBloc({@required Ticker ticker})       : assert(ticker != null),         _ticker = ticker;   /// 初始化状态   @override   TimerState get initialState => Ready(_duration);   @override   Stream<TimerState> mapEventToState(     TimerEvent event,   ) async* {     print('$event');     if (event is Start) {       yield* _mapStartToState(event);     } else if (event is Tick) {       yield* _mapTickToState(event);     } else if (event is Pause) {       yield* _mapPauseToState(event);     } else if (event is Resume) {       yield* _mapResumeToState(event);     } else if (event is Reset) {       yield* _mapResetToState(event);     }   }   @override   Future<void> close() {     _tickerSubscription?.cancel();     return super.close();   }   /// 处理开始事件   Stream<TimerState> _mapStartToState(Start start) async* {     // 运行状态     yield Running(start.duration);     // 取消订阅     _tickerSubscription?.cancel();     // 创建订阅     _tickerSubscription =         _ticker.tick(ticks: start.duration).listen((duration) {       add(Tick(duration: duration));     });   }   /// 处理定时器事件   Stream<TimerState> _mapTickToState(Tick tick) async* {     yield tick.duration > 0 ? Running(tick.duration) : Finished();   }   /// 处理暂停事件   Stream<TimerState> _mapPauseToState(Pause pause) async* {     if (state is Running) {       _tickerSubscription?.pause();       yield Paused(state.duration);     }   }   /// 处理恢复状态   Stream<TimerState> _mapResumeToState(Resume resume) async* {     if (state is Paused) {       _tickerSubscription?.resume();       yield Running(state.duration);     }   }   /// 处理重置状态   Stream<TimerState> _mapResetToState(Reset reset) async* {     _tickerSubscription?.cancel();     yield Ready(_duration);   } }

6. 界面实现

实现定时器显示
timer_test.dart

import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:state_manage/timer/bloc/bloc.dart'; import 'package:state_manage/timer/ticker.dart'; /// 定时器 class TimerTest extends StatelessWidget {   @override   Widget build(BuildContext context) {     return MaterialApp(       theme: ThemeData(         primaryColor: Color.fromRGBO(109, 234, 255, 1),         accentColor: Color.fromRGBO(72, 74, 126, 1),         brightness: Brightness.dark,       ),       title: 'Flutter Timer',       home: BlocProvider(         create: (ctx) => TimerBloc(ticker: Ticker()),         child: Timer(),       ),     );   } } /// 定时器页面 class Timer extends StatelessWidget{   /// 字体样式   static const TextStyle timerTextStyle = TextStyle(     fontSize: 60,     fontWeight: FontWeight.bold   );   @override   Widget build(BuildContext context) {     return Scaffold(       appBar: AppBar(title: Text('Flutter Time')),       body: Column(         mainAxisAlignment: MainAxisAlignment.center,         crossAxisAlignment: CrossAxisAlignment.center,         children: <Widget>[           Padding(             padding: EdgeInsets.symmetric(vertical: 100.0),             child: Center(               child: BlocBuilder<TimerBloc, TimerState>(                 builder: (ctx, state) {                   // 分钟格式化                   final String minuteStr = ((state.duration / 60) % 60).floor().toString().padLeft(2, '0');                   // 秒数格式化                   final String secondStr = (state.duration % 60).floor().toString().padLeft(2, '0');                   return Text(                     '$minuteStr : $secondStr',                     style: Timer.timerTextStyle,                   );                 },               ),             ),           )         ],       ),     );   } }

添加背景
timer_background.dart

import 'package:flutter/material.dart'; import 'package:wave/config.dart'; import 'package:wave/wave.dart'; /// 定时器背景 class Background extends StatelessWidget {   @override   Widget build(BuildContext context) {     return WaveWidget(       config: CustomConfig(         gradients: [           [             Color.fromRGBO(72, 74, 126, 1),             Color.fromRGBO(125, 170, 206, 1),             Color.fromRGBO(184, 189, 245, 0.7)           ],           [             Color.fromRGBO(72, 74, 126, 1),             Color.fromRGBO(125, 170, 206, 1),             Color.fromRGBO(172, 182, 219, 0.7)           ],           [             Color.fromRGBO(72, 73, 126, 1),             Color.fromRGBO(125, 170, 206, 1),             Color.fromRGBO(190, 238, 246, 0.7)           ]         ],         durations: [19440, 10800, 6000],         heightPercentages: [0.03, 0.01, 0.02],         gradientBegin: Alignment.bottomCenter,         gradientEnd: Alignment.topCenter       ),       size: Size(double.infinity, double.infinity),       waveAmplitude: 25,       backgroundColor: Colors.blue[50],     );   } }

timer_test.dart

 /// 定时器页面 class Timer extends StatelessWidget {   /// 字体样式   static const TextStyle timerTextStyle =       TextStyle(fontSize: 60, fontWeight: FontWeight.bold);   @override   Widget build(BuildContext context) {     return Scaffold(       appBar: AppBar(title: Text('Flutter Time')),       body: Stack(         children: <Widget>[           Background(),           Column(             // ... 省略内容           )         ],       ),     );   } }

添加定时器动作
timer_actions.dart

import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:state_manage/timer/bloc/bloc.dart'; /// 动作 class TimerActions extends StatelessWidget {   @override   Widget build(BuildContext context) {     return Row(       mainAxisAlignment: MainAxisAlignment.spaceEvenly,       children: _mapStateToActionButtons(timerBloc: BlocProvider.of<TimerBloc>(context)),     );   }   /// 创建动作按钮   /// @param timerBloc 定时器Bloc   List<Widget> _mapStateToActionButtons({TimerBloc timerBloc}) {     // 定时器当前状态     final TimerState currentState = timerBloc.state;     // 根据不同状态返回不同视图     if (currentState is Ready) {       return [FloatingActionButton(         child: Icon(Icons.play_arrow),         onPressed: () => timerBloc.add(Start(duration: currentState.duration)),       )];     } else if (currentState is Running) {       return [         FloatingActionButton(           child: Icon(Icons.pause),           onPressed: () => timerBloc.add(Pause()),         ),         FloatingActionButton(           child: Icon(Icons.replay),           onPressed: () => timerBloc.add(Reset()),         )       ];     } else if (currentState is Paused) {       return [         FloatingActionButton(           child: Icon(Icons.play_arrow),           onPressed: () => timerBloc.add(Resume()),         ),         FloatingActionButton(           child: Icon(Icons.replay),           onPressed: () => timerBloc.add(Reset()),         )       ];     } else if (currentState is Finished) {       return [         FloatingActionButton(           child: Icon(Icons.replay),           onPressed: () => timerBloc.add(Reset()),         )       ];     } else {       return [];     }   } }

在界面设置动作
timer_test.dart

/// 定时器页面 class Timer extends StatelessWidget {   /// 字体样式   static const TextStyle timerTextStyle =       TextStyle(fontSize: 60, fontWeight: FontWeight.bold);   @override   Widget build(BuildContext context) {     return Scaffold(       appBar: AppBar(title: Text('Flutter Timer')),       body: Stack(         children: <Widget>[           Background(),           Column(             mainAxisAlignment: MainAxisAlignment.center,             crossAxisAlignment: CrossAxisAlignment.center,             children: <Widget>[               Padding(                 // ...               ),               BlocBuilder<TimerBloc, TimerState>(                 condition: (previousState, currentState) => currentState.runtimeType != previousState.runtimeType,                 builder: (ctx, state) => TimerActions(),               )             ],           )         ],       ),     );   } }

效果图



示例 flutter 定时器

需要 登录 后方可回复, 如果你还没有账号请 注册新账号