千家信息网

Flutter状态管理Bloc之定时器怎么实现

发表于:2024-11-24 作者:千家信息网编辑
千家信息网最后更新 2024年11月24日,小编给大家分享一下Flutter状态管理Bloc之定时器怎么实现,希望大家阅读完这篇文章之后都有所收获,下面让我们一起去探讨吧!具体内容如下1. 依赖dependencies: flutter_bl
千家信息网最后更新 2024年11月24日Flutter状态管理Bloc之定时器怎么实现

小编给大家分享一下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 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'; /// 定时器状态@immutableabstract class TimerState extends Equatable{  /// 时间  final int duration;   /// 构造方法   const TimerState(this.duration);   @override  List 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'; /// 定时器事件@immutableabstract class TimerEvent extends Equatable{   const TimerEvent();   @override  List 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 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'; /// 定时器Blocclass TimerBloc extends Bloc {  /// 定时器时间  final int _duration = 60;  /// 定时器数据流  final Ticker _ticker;  // 流订阅  StreamSubscription _tickerSubscription;   TimerBloc({@required Ticker ticker})      : assert(ticker != null),        _ticker = ticker;   /// 初始化状态  @override  TimerState get initialState => Ready(_duration);   @override  Stream 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 close() {    _tickerSubscription?.cancel();    return super.close();  }   /// 处理开始事件  Stream _mapStartToState(Start start) async* {    // 运行状态    yield Running(start.duration);    // 取消订阅    _tickerSubscription?.cancel();    // 创建订阅    _tickerSubscription =        _ticker.tick(ticks: start.duration).listen((duration) {      add(Tick(duration: duration));    });  }   /// 处理定时器事件  Stream _mapTickToState(Tick tick) async* {    yield tick.duration > 0 ? Running(tick.duration) : Finished();  }   /// 处理暂停事件  Stream _mapPauseToState(Pause pause) async* {    if (state is Running) {      _tickerSubscription?.pause();      yield Paused(state.duration);    }  }   /// 处理恢复状态  Stream _mapResumeToState(Resume resume) async* {    if (state is Paused) {      _tickerSubscription?.resume();      yield Running(state.duration);    }  }   /// 处理重置状态  Stream _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: [          Padding(            padding: EdgeInsets.symmetric(vertical: 100.0),            child: Center(              child: BlocBuilder(                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: [          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(context)),    );  }   /// 创建动作按钮  /// @param timerBloc 定时器Bloc  List _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: [          Background(),          Column(            mainAxisAlignment: MainAxisAlignment.center,            crossAxisAlignment: CrossAxisAlignment.center,            children: [              Padding(                // ...              ),              BlocBuilder(                condition: (previousState, currentState) => currentState.runtimeType != previousState.runtimeType,                builder: (ctx, state) => TimerActions(),              )            ],          )        ],      ),    );  }}

效果图

看完了这篇文章,相信你对"Flutter状态管理Bloc之定时器怎么实现"有了一定的了解,如果想了解更多相关知识,欢迎关注行业资讯频道,感谢各位的阅读!

0