Flutter Counter
In the following tutorial, we’re going to build a Counter in Flutter using the Bloc library.
- Observe state changes with BlocObserver.
- BlocProvider, Flutter widget which provides a bloc to its children.
- BlocBuilder, Flutter widget that handles building the widget in response to new states.
- Using Cubit instead of Bloc. What’s the difference?
- Adding events with context.read.
We’ll start off by creating a brand new Flutter project
We can then go ahead and replace the contents of pubspec.yaml
with
and then install all of our dependencies
The application uses a feature-driven directory structure. This project structure enables us to scale the project by having self-contained features. In this example we will only have a single feature (the counter itself) but in more complex applications we can have hundreds of different features.
The first thing we’re going to take a look at is how to create a BlocObserver
which will help us observe all state changes in the application.
Let’s create lib/counter_observer.dart
:
In this case, we’re only overriding onChange
to see all state changes that occur.
Next, let’s replace the contents of lib/main.dart
with:
We’re initializing the CounterObserver
we just created and calling runApp
with the CounterApp
widget which we’ll look at next.
Let’s create lib/app.dart
:
CounterApp
will be a MaterialApp
and is specifying the home
as CounterPage
.
Let’s take a look at CounterPage
next!
Let’s create lib/counter/view/counter_page.dart
:
The CounterPage
widget is responsible for creating a CounterCubit
(which we will look at next) and providing it to the CounterView
.
Let’s create lib/counter/cubit/counter_cubit.dart
:
The CounterCubit
class will expose two methods:
increment
: adds 1 to the current statedecrement
: subtracts 1 from the current state
The type of state the CounterCubit
is managing is just an int
and the initial state is 0
.
Next, let’s take a look at the CounterView
which will be responsible for consuming the state and interacting with the CounterCubit
.
Let’s create lib/counter/view/counter_view.dart
:
The CounterView
is responsible for rendering the current count and rendering two FloatingActionButtons to increment/decrement the counter.
A BlocBuilder
is used to wrap the Text
widget in order to update the text any time the CounterCubit
state changes. In addition, context.read<CounterCubit>()
is used to look-up the closest CounterCubit
instance.
Create lib/counter/view/view.dart
:
Add view.dart
to export all public facing parts of counter view.
Let’s create lib/counter/counter.dart
:
Add counter.dart
to export all the public facing parts of the counter feature.
That’s it! We’ve separated the presentation layer from the business logic layer. The CounterView
has no idea what happens when a user presses a button; it just notifies the CounterCubit
. Furthermore, the CounterCubit
has no idea what is happening with the state (counter value); it’s simply emitting new states in response to the methods being called.
We can run our app with flutter run
and can view it on our device or simulator/emulator.
The full source (including unit and widget tests) for this example can be found here.