원문: Bloc / Recipes / Flutter / Show SnackBar
In this recipe, we're going to take a look at how to use
BlocListener
to show aSnackBar
in response to a state change in a bloc.
Let's build a basic DataBloc
which will handle DataEvents
and output DataStates
.
For simplicity, our DataBloc
will only respond to a single DataEvent
called FetchData
.
import 'package:meta/meta.dart';
@immutable
abstract class DataEvent {}
class FetchData extends DataEvent {}
Our DataBloc
can have one of three different DataStates
:
Initial
- the initial state before any events are dispatchedLoading
- the state of the bloc while it is asynchronously "fetching data"Success
- the state of the bloc when it has successfully "fetched data"
import 'package:meta/meta.dart';
@immutable
abstract class DataState {}
class Initial extends DataState {}
class Loading extends DataState {}
class Success extends DataState {}
Our DataBloc
should look something like this:
import 'package:bloc/bloc.dart';
class DataBloc extends Bloc<DataEvent, DataState> {
@override
DataState get initialState => Initial();
@override
Stream<DataState> mapEventToState(
DataEvent event,
) async* {
if (event is FetchData) {
yield Loading();
await Future.delayed(Duration(seconds: 2));
yield Success();
}
}
}
Note: We're using Future.delayed
to simulate latency.
Now let's take a look at how to hook up our DataBloc
to a widget and show a SnackBar
in response to a success state.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
bloc: DataBloc(),
child: MaterialApp(
home: Home(),
),
);
}
}
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Home')),
body: BlocListener(
bloc: BlocProvider.of<DataBloc>(context),
listener: (BuildContext context, DataState state) {
if (state is Success) {
Scaffold.of(context).showSnackBar(
SnackBar(
backgroundColor: Colors.green,
content: Text('Success'),
),
);
}
},
child: BlocBuilder(
bloc: BlocProvider.of<DataBloc>(context),
builder: (BuildContext context, DataState state) {
if (state is Initial) {
return Center(child: Text('Press the Button'));
}
if (state is Loading) {
return Center(child: CircularProgressIndicator());
}
if (state is Success) {
return Center(child: Text('Success'));
}
},
),
),
floatingActionButton: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FloatingActionButton(
child: Icon(Icons.play_arrow),
onPressed: () {
BlocProvider.of<DataBloc>(context).dispatch(FetchData());
},
),
],
),
);
}
}
We use the BlocListener
widget in order to DO THINGS in response to state changes in our DataBloc
.
We use the BlocBuilder
widget in order to RENDER WIDGETS in response to state changes in our DataBloc
.
We should NEVER "do things" in response to state changes in the builder
method of BlocBuilder
because that method can be called many times by the Flutter framework. The builder
method should be a pure function that just returns a widget in response to the state of the bloc.
The full source for this recipe can be found here.
이전: Github Search
다음: Navigation