class Ticker{
Stream tick({int ticks}){
return Stream.periodic(Duration(seconds: 1),(v){
return ticks - v - 1;
}).take(ticks);
}
}
这是一个定时器,我们没有使用timer,而是直接使用stream来实现。
TimerInitial 定时器初始化
TimerRunInProgress 定时器过程
TimerRunPause 定时器暂停
TimerRunComplete 定时器完成
import 'package:equatable/equatable.dart';
abstract class TimerState extends Equatable{
final int duration;
const TimerState(this.duration);
@override
List
TimerStarted 播放事件
TimerPaused 暂停事件
TimerResumed 恢复事件
TimerReset 重置事件
TimerTicked 定时器过程事件
import 'package:equatable/equatable.dart';
import 'package:flutter/material.dart';
abstract class TimerEvent extends Equatable{
const TimerEvent();
@override
List
这里的事件分出来,可以根据我们的分析知道,只有定时器的开始和定时器的过程这两个事件可以接受我们的定时器当时的时间。其余的都只是单独的事件。
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{
final Ticker _ticker; //定时器
final int _duration = 60; //定时器的时间一分钟
TimerBloc({@required Ticker ticker})
: assert(ticker != null),
_ticker = ticker; //初始化_ticker
StreamSubscription _tickerSubscription;
@override
TimerState get initialState => TimerInitial(_duration);
@override
Stream 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 close() {
return super.close();
_tickerSubscription?.cancel();
}
//定时器开始
Stream _mapTimerStartedToState(TimerStarted started) async* {
yield TimerRunInProgress(_duration);
_tickerSubscription?.cancel();
_tickerSubscription = _ticker
.tick(ticks: started.duration)
.listen((duration) => add(TimerTicked(duration: duration)));
}
//定时器读秒
Stream _mapTimerTickedToState(TimerTicked tick) async* {
yield tick.duration > 0 ? TimerRunInProgress(tick.duration) : TimerRunComplete();
}
//定时器暂停
Stream _mapTimerPausedToState(TimerPaused pause) async* {
if(state is TimerRunInProgress){
_tickerSubscription?.pause();
yield TimerRunPause(state.duration);
}
}
//定时器暂停后又恢复
Stream _mapTimerResumedToState(TimerResumed resume) async* {
if(state is TimerRunPause){
_tickerSubscription?.resume();
yield TimerRunInProgress(state.duration);
}
}
Stream _mapTimerResetToState(TimerReset reset) async* {
_tickerSubscription?.cancel();
yield TimerInitial(_duration);
}
@override
void onTransition(Transition transition) {
super.onTransition(transition);
print('transition::::$transition');
}
}
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(
create: (context) => TimerBloc(ticker: Ticker()),
child: 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: [
WavesBackground(),
Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(
padding: EdgeInsets.symmetric(vertical: 100),
child: Center(
child: BlocBuilder(
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(
condition: (preState,state){
return state.runtimeType != preState.runtimeType;
},
builder: (context,state){
return 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(context),
),
);
}
List _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 [];
}
}
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方法去实现。