Flutter状态管理之BLoc----实现计算器功能

1.我们先安装依赖

2.写一个ticker.dart

class Ticker{
  Stream<int> tick({int ticks}){
    return Stream.periodic(Duration(seconds: 1),(v){
      return ticks - v - 1;
    }).take(ticks);
  }
}

这是一个定时器,我们没有使用timer,而是直接使用stream来实现。

3.timer的state区分

TimerInitial  定时器初始化
TimerRunInProgress  定时器过程
TimerRunPause  定时器暂停
TimerRunComplete  定时器完成

import 'package:equatable/equatable.dart';

abstract class TimerState extends Equatable{
  final int duration;

  const TimerState(this.duration);

  @override
  List<Object> get props => [duration];
}


class TimerInitial extends TimerState{
  const TimerInitial(int duration) : super(duration);

  @override
  String toString() => 'TimerInitial { duration: $duration }';
}

class TimerRunPause extends TimerState{
  const TimerRunPause(int duration) : super(duration);

  @override
  String toString() => 'TimerRunPause { duration: $duration }';
}

class TimerRunInProgress extends TimerState{
  const TimerRunInProgress(int duration) : super(duration);

  @override
  String toString() => 'TimerRunInProgress { duration: $duration }';
}

class TimerRunComplete extends TimerState{
  const TimerRunComplete() : super(0);
}

4.timer的event区分

TimerStarted  播放事件
TimerPaused  暂停事件
TimerResumed  恢复事件
TimerReset  重置事件
TimerTicked  定时器过程事件

import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';

abstract class TimerEvent extends Equatable{
  const TimerEvent();

  @override
  List<Object> get props => [];
}

class TimerStarted extends TimerEvent{
  final int duration;

  TimerStarted({@required this.duration});

  @override
  String toString() => 'TimerStarted { duration: $duration }';
}

class TimerPaused extends TimerEvent{}

class TimerResumed extends TimerEvent{}

class TimerReset extends TimerEvent{}

class TimerTicked extends TimerEvent{
  final int duration;

  TimerTicked({@required this.duration});

  @override
  List<Object> get props => [duration];

  @override
  String toString() => 'TimerTicked { duration: $duration }';
}

这里的事件分出来,可以根据我们的分析知道,只有定时器的开始和定时器的过程这两个事件可以接受我们的定时器当时的时间。其余的都只是单独的事件。

5.timer的state和event组装成Bloc


import 'dart:async';

import 'package:bloc/bloc.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutterapp1111/ticker.dart';
import 'package:flutterapp1111/bloc/timer_event.dart';
import 'package:flutterapp1111/bloc/timer_state.dart';

class TimerBloc extends Bloc<TimerEvent,TimerState>{
  final Ticker _ticker;  //定时器
  final int _duration = 60;  //定时器的时间一分钟

  TimerBloc({@required Ticker ticker})
      : assert(ticker != null),
        _ticker = ticker;  //初始化_ticker

  StreamSubscription<int> _tickerSubscription;

  @override
  TimerState get initialState => TimerInitial(_duration);

  @override
  Stream<TimerState> mapEventToState(TimerEvent event) async* {
    if(event is TimerStarted){
      yield* _mapTimerStartedToState(event);
    }else if(event is TimerTicked){
      yield* _mapTimerTickedToState(event);
    }else if(event is TimerPaused){
      yield* _mapTimerPausedToState(event);
    }else if(event is TimerResumed){
      yield* _mapTimerResumedToState(event);
    }else if(event is TimerReset){
      yield* _mapTimerResetToState(event);
    }
  }

  @override
  Future<void> close() {
    return super.close();
    _tickerSubscription?.cancel();
  }

  //定时器开始
  Stream<TimerState> _mapTimerStartedToState(TimerStarted started) async* {
    yield TimerRunInProgress(_duration);
    _tickerSubscription?.cancel();
    _tickerSubscription = _ticker
        .tick(ticks: started.duration)
        .listen((duration) => add(TimerTicked(duration: duration)));
  }

  //定时器读秒
  Stream<TimerState> _mapTimerTickedToState(TimerTicked tick) async* {
    yield tick.duration > 0 ? TimerRunInProgress(tick.duration) : TimerRunComplete();
  }

  //定时器暂停
  Stream<TimerState> _mapTimerPausedToState(TimerPaused pause) async* {
    if(state is TimerRunInProgress){
      _tickerSubscription?.pause();
      yield TimerRunPause(state.duration);
    }
  }

  //定时器暂停后又恢复
  Stream<TimerState> _mapTimerResumedToState(TimerResumed resume) async* {
    if(state is TimerRunPause){
      _tickerSubscription?.resume();
      yield TimerRunInProgress(state.duration);
    }
  }

  Stream<TimerState> _mapTimerResetToState(TimerReset reset) async* {
    _tickerSubscription?.cancel();
    yield TimerInitial(_duration);
  }

  @override
  void onTransition(Transition<TimerEvent, TimerState> transition) {
    super.onTransition(transition);
    print('transition::::$transition');
  }
}

6.MyApp

import 'package:bloc/bloc.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutterapp1111/bloc/bloc.dart';
import 'package:flutterapp1111/ticker.dart';
import 'package:flutterapp1111/timer_page.dart';

void main() {

  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primaryColor: Color.fromRGBO(109, 234, 255, 1),
        accentColor: Color.fromRGBO(72, 74, 126, 1),
        brightness: Brightness.dark,
      ),
      home: BlocProvider<TimerBloc>(
        create: (context) => TimerBloc(ticker: Ticker()),
        child: TimerPage(),
      ),
    );
  }
}

7.TimerPage


import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutterapp1111/actions_page.dart';
import 'package:flutterapp1111/bloc/bloc.dart';
import 'package:flutterapp1111/waves_background.dart';

class TimerPage extends StatelessWidget {

  static const TextStyle timerTextStyle = TextStyle(
    fontSize: 60,
    fontWeight: FontWeight.bold
  );

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('BLoc Timer'),
      ),
      body: Stack(
        children: <Widget>[
          WavesBackground(),
          Column(
            mainAxisAlignment: MainAxisAlignment.center,
            crossAxisAlignment: CrossAxisAlignment.center,
            children: <Widget>[
              Padding(
                padding: EdgeInsets.symmetric(vertical: 100),
                child: Center(
                  child: BlocBuilder<TimerBloc,TimerState>(
                    builder: (context,state){
                      final String minutesStr = ((state.duration / 60) % 60)
                          .floor()
                          .toString()
                          .padLeft(2,"0");
                      final String secondsStr =
                      (state.duration % 60)
                          .floor()
                          .toString()
                          .padLeft(2, '0');

                      return Text(
                        '$minutesStr:$secondsStr',
                        style: TimerPage.timerTextStyle,
                      );
                    },
                  ),
                ),
              ),
              BlocBuilder<TimerBloc,TimerState>(
                condition: (preState,state){
                  return state.runtimeType != preState.runtimeType;
                },
                builder: (context,state){
                  return ActionsPage();
                },
              )
            ],
          )
        ],
      ),
    );
  }
}

8.ActionsPage

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutterapp1111/bloc/bloc.dart';

class ActionsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      children: _mapStateToActionButtons(
        timerBloc: BlocProvider.of<TimerBloc>(context),
      ),
    );
  }

  List<Widget> _mapStateToActionButtons({TimerBloc timerBloc}){
    final TimerState currentState = timerBloc.state;
    if (currentState is TimerInitial) {
      return [
        FloatingActionButton(
          child: Icon(Icons.play_arrow),
          onPressed: () =>
              timerBloc.add(TimerStarted(duration: currentState.duration)),
        ),
      ];
    }
    if (currentState is TimerRunInProgress) {
      return [
        FloatingActionButton(
          child: Icon(Icons.pause),
          onPressed: () => timerBloc.add(TimerPaused()),
        ),
        FloatingActionButton(
          child: Icon(Icons.replay),
          onPressed: () => timerBloc.add(TimerReset()),
        ),
      ];
    }
    if (currentState is TimerRunPause) {
      return [
        FloatingActionButton(
          child: Icon(Icons.play_arrow),
          onPressed: () => timerBloc.add(TimerResumed()),
        ),
        FloatingActionButton(
          child: Icon(Icons.replay),
          onPressed: () => timerBloc.add(TimerReset()),
        ),
      ];
    }
    if (currentState is TimerRunComplete) {
      return [
        FloatingActionButton(
          child: Icon(Icons.replay),
          onPressed: () => timerBloc.add(TimerReset()),
        ),
      ];
    }
    return [];
  }
}

9.WavesBackground

import 'package:flutter/material.dart';
import 'package:wave/config.dart';
import 'package:wave/wave.dart';

class WavesBackground 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: [19400,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],
    );
  }
}

以上就是BLoc定时器的设置。
这里说一下没有什么好讲解的,就是把state和event分开,我们的点击事件和点击的功能分开。托管于stream实现。

state是页面显示的状态,里面的数据也托管于各自的state。
event是页面的响应事件,通过bloc的add方法去实现。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值