Skip to content

Instantly share code, notes, and snippets.

@felangel
Created June 26, 2019 02:52
Show Gist options
  • Select an option

  • Save felangel/ada82ee2bfc9178b1a772a3ec4fa77bc to your computer and use it in GitHub Desktop.

Select an option

Save felangel/ada82ee2bfc9178b1a772a3ec4fa77bc to your computer and use it in GitHub Desktop.
Flutter Bloc Stepper
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:bloc/bloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:equatable/equatable.dart';
abstract class StepperEvent extends Equatable {
StepperEvent([List props = const []]) : super(props);
}
class StepTapped extends StepperEvent {
final int step;
StepTapped({@required this.step}) : super([step]);
@override
String toString() => 'StepTapped { step: $step }';
}
class StepCancelled extends StepperEvent {
@override
String toString() => 'StepCancelled';
}
class StepContinue extends StepperEvent {
@override
String toString() => 'StepContinue';
}
class StepperState extends Equatable {
final int step;
final int maxSteps;
StepperState({
@required this.step,
@required this.maxSteps,
}) : super([step, maxSteps]);
StepperState copyWith({int step, int maxSteps}) {
return StepperState(
step: step ?? this.step,
maxSteps: maxSteps ?? this.maxSteps,
);
}
@override
String toString() => 'StepperState { step: $step, maxSteps: $maxSteps }';
}
class StepperBloc extends Bloc<StepperEvent, StepperState> {
final int maxSteps;
StepperBloc({@required this.maxSteps});
@override
StepperState get initialState => StepperState(step: 0, maxSteps: maxSteps);
@override
void onTransition(Transition<StepperEvent, StepperState> transition) {
super.onTransition(transition);
print(transition);
}
@override
Stream<StepperState> mapEventToState(StepperEvent event) async* {
if (event is StepTapped) {
yield currentState.copyWith(step: event.step);
} else if (event is StepCancelled) {
yield currentState.copyWith(
step: currentState.step - 1 >= 0 ? currentState.step - 1 : 0,
);
} else if (event is StepContinue) {
yield currentState.copyWith(
step: currentState.step + 1 < maxSteps ? currentState.step + 1 : 0,
);
}
}
}
void main() {
final List<Step> steps = [
Step(
title: Text("Step 1"),
content: Text("Hello!"),
isActive: true,
),
Step(
title: Text("Step 2"),
content: Text("World!"),
state: StepState.editing,
isActive: true,
),
Step(
title: Text("Step 3"),
content: Text("Hello World!"),
isActive: true,
),
];
runApp(
MaterialApp(
home: BlocProvider(
builder: (context) => StepperBloc(maxSteps: steps.length),
child: MyHome(steps: steps),
),
),
);
}
class MyHome extends StatelessWidget {
final List<Step> steps;
MyHome({Key key, @required this.steps}) : super(key: key);
@override
Widget build(BuildContext context) {
print('MyHome build');
final stepperBloc = BlocProvider.of<StepperBloc>(context);
return Scaffold(
appBar: AppBar(
title: Text('Flutter Bloc Stepper'),
),
body: Container(
child: BlocBuilder(
bloc: stepperBloc,
builder: (BuildContext context, StepperState state) {
return Stepper(
currentStep: state.step,
steps: steps,
type: StepperType.vertical,
onStepTapped: (step) {
stepperBloc.dispatch(StepTapped(step: step));
},
onStepCancel: () {
stepperBloc.dispatch(StepCancelled());
},
onStepContinue: () {
stepperBloc.dispatch(StepContinue());
},
);
},
),
),
);
}
}
@felangel
Copy link
Author

Thanks for clarifying! Yeah I definitely recommend separating things where it makes sense because, like you said, it helps with reuse and modularity.

That's awesome! Thanks so much for the positive feedback and don't hesitate to ask any more questions regarding the bloc library either by opening an issue or posting a question in the chat 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment