您好,登錄后才能下訂單哦!
小編給大家分享一下Flutter狀態(tài)管理Bloc之定時(shí)器怎么實(shí)現(xiàn),希望大家閱讀完這篇文章之后都有所收獲,下面讓我們一起去探討吧!
具體內(nèi)容如下
1. 依賴
dependencies: flutter_bloc: ^2.1.1 equatable: ^1.0.1 wave: ^0.0.8
2. Ticker
Ticker 用于產(chǎn)生定時(shí)器的數(shù)據(jù)流。
/// 定時(shí)器數(shù)據(jù)源 class Ticker { /// 定時(shí)器數(shù)據(jù)源 /// @param ticks 時(shí)間 Stream<int> tick({int ticks}){ return Stream.periodic(Duration(seconds: 1), (x) => ticks - x - 1).take(ticks); } }
3. TimerBloc
創(chuàng)建 TimerBloc 用于消費(fèi)Ticker, 我們需要?jiǎng)?chuàng)建定時(shí)器狀態(tài),定時(shí)器事件兩個(gè)輔助類。其中定時(shí)器的狀態(tài)有
Ready(準(zhǔn)備從指定的持續(xù)時(shí)間開始倒計(jì)時(shí))
Running(從指定持續(xù)時(shí)間開始遞減計(jì)數(shù))
Paused(在剩余的持續(xù)時(shí)間內(nèi)暫停)
Finished已完成,剩余持續(xù)時(shí)間為0
import 'package:equatable/equatable.dart'; import 'package:meta/meta.dart'; /// 定時(shí)器狀態(tài) @immutable abstract class TimerState extends Equatable{ /// 時(shí)間 final int duration; /// 構(gòu)造方法 const TimerState(this.duration); @override List<Object> get props => [this.duration]; } /// 準(zhǔn)備狀態(tài) class Ready extends TimerState { const Ready(int duration) : super(duration); @override String toString() => 'Ready { duration: $duration }'; } /// 暫停狀態(tài) class Paused extends TimerState { const Paused(int duration) : super(duration); @override String toString() => 'Paused { duration: $duration }'; } /// 運(yùn)行狀態(tài) class Running extends TimerState { const Running(int duration) : super(duration); @override String toString() => 'Running { duration: $duration }'; } /// 完成狀態(tài) class Finished extends TimerState{ const Finished() : super(0); }
所有的State都繼承自抽象類TimerState,因?yàn)椴徽撛谀膫€(gè)狀態(tài),我們都需要知道剩余時(shí)間。
4. TimerEvent
我們需要處理的事件有
Start?(通知TimerBloc定時(shí)器應(yīng)該開始)
Pause?(通知TimerBloc計(jì)時(shí)器應(yīng)該暫停)
Resume(通知TimerBloc應(yīng)該恢復(fù)計(jì)時(shí)器)
Reset?(通知TimerBloc定時(shí)器應(yīng)重置為原始狀態(tài))
Tick?(通知TimerBloc需要更新剩余時(shí)間)
import 'package:equatable/equatable.dart'; import 'package:meta/meta.dart'; /// 定時(shí)器事件 @immutable abstract class TimerEvent extends Equatable{ const TimerEvent(); @override List<Object> get props => []; } /// 開始時(shí)間 class Start extends TimerEvent { /// 定時(shí)器時(shí)間 final int duration; const Start({@required this.duration}); @override String toString() => 'Start { duration: $duration }'; } /// 暫停事件 class Paused extends TimerEvent {} /// 恢復(fù)狀態(tài) class Resumed extends TimerEvent {} /// 重置狀態(tài) class Reset extends TimerEvent {} /// 定時(shí)器事件 class Tick extends TimerEvent { /// 當(dāng)前時(shí)間 final int duration; const Tick({@required this.duration}); @override List<Object> get props => [this.duration]; @override String toString() => 'Tick { duration: $duration }'; }
5. TimerBloc 實(shí)現(xiàn)
1.初始化狀態(tài)Ready(_duration)
2.創(chuàng)建Ticker對(duì)象, 用戶獲取數(shù)據(jù)流
3.實(shí)現(xiàn)mapEventToState方法
4.當(dāng)event為Start時(shí), 需要開啟數(shù)據(jù)流
5.創(chuàng)建StreamSubscription, 處理流的不同狀態(tài), 并在bloc的close方法中關(guān)閉它
6.當(dāng)event為Tick時(shí), 需要處理數(shù)據(jù)的更新
7.當(dāng)event為Pause時(shí), 需要停止定時(shí)器
8.當(dāng)event為Resume時(shí), 需要重新啟動(dòng)定時(shí)器
9.當(dāng)event為reset時(shí), 需要重置定時(shí)器
import 'dart:async'; import 'package:bloc/bloc.dart'; import 'package:flutter/material.dart'; import 'package:state_manage/timer/ticker.dart'; import './bloc.dart'; /// 定時(shí)器Bloc class TimerBloc extends Bloc<TimerEvent, TimerState> { /// 定時(shí)器時(shí)間 final int _duration = 60; /// 定時(shí)器數(shù)據(jù)流 final Ticker _ticker; // 流訂閱 StreamSubscription<int> _tickerSubscription; TimerBloc({@required Ticker ticker}) : assert(ticker != null), _ticker = ticker; /// 初始化狀態(tài) @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* { // 運(yùn)行狀態(tài) yield Running(start.duration); // 取消訂閱 _tickerSubscription?.cancel(); // 創(chuàng)建訂閱 _tickerSubscription = _ticker.tick(ticks: start.duration).listen((duration) { add(Tick(duration: duration)); }); } /// 處理定時(shí)器事件 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); } } /// 處理恢復(fù)狀態(tài) Stream<TimerState> _mapResumeToState(Resume resume) async* { if (state is Paused) { _tickerSubscription?.resume(); yield Running(state.duration); } } /// 處理重置狀態(tài) Stream<TimerState> _mapResetToState(Reset reset) async* { _tickerSubscription?.cancel(); yield Ready(_duration); } }
6. 界面實(shí)現(xiàn)
實(shí)現(xiàn)定時(shí)器顯示
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'; /// 定時(shí)器 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(), ), ); } } /// 定時(shí)器頁面 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'); // 秒數(shù)格式化 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'; /// 定時(shí)器背景 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
/// 定時(shí)器頁面 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( // ... 省略內(nèi)容 ) ], ), ); } }
添加定時(shí)器動(dòng)作
timer_actions.dart
import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:state_manage/timer/bloc/bloc.dart'; /// 動(dòng)作 class TimerActions extends StatelessWidget { @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: _mapStateToActionButtons(timerBloc: BlocProvider.of<TimerBloc>(context)), ); } /// 創(chuàng)建動(dòng)作按鈕 /// @param timerBloc 定時(shí)器Bloc List<Widget> _mapStateToActionButtons({TimerBloc timerBloc}) { // 定時(shí)器當(dāng)前狀態(tài) final TimerState currentState = timerBloc.state; // 根據(jù)不同狀態(tài)返回不同視圖 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 []; } } }
在界面設(shè)置動(dòng)作
timer_test.dart
/// 定時(shí)器頁面 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(), ) ], ) ], ), ); } }
效果圖
看完了這篇文章,相信你對(duì)“Flutter狀態(tài)管理Bloc之定時(shí)器怎么實(shí)現(xiàn)”有了一定的了解,如果想了解更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。