網站首頁 編程語言 正文
本文實例為大家分享了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(), ? ? ? ? ? ? ? ) ? ? ? ? ? ? ], ? ? ? ? ? ) ? ? ? ? ], ? ? ? ), ? ? ); ? } }
效果圖
原文鏈接:https://blog.csdn.net/mazaiting/article/details/103523047
相關推薦
- 2022-10-21 C#中匿名方法與委托的關系介紹_C#教程
- 2022-08-21 使用?DataAnt?監控?Apache?APISIX的原理解析_Linux
- 2022-03-26 Android實現調用攝像頭拍照并存儲照片_Android
- 2021-12-06 c#二叉樹存儲介紹_C#教程
- 2023-01-30 python第三方異步日志庫loguru簡介_python
- 2022-05-04 python運算符+條件結構+循環結構_python
- 2022-12-21 redis?setIfAbsent返回null的問題及解決_Redis
- 2022-08-23 Rx.NET庫中IDisposable對象的用法_實用技巧
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支