Flutter Bloc Package

Pub Build Status codecov Flutter.io Awesome Flutter Flutter Samples Star on GitHub Gitter License: MIT


A Flutter package that helps implement the BLoC pattern.

This package is built to work with bloc.

Bloc Widgets

BlocBuilder is a Flutter widget which requires a Bloc and a builder function. BlocBuilder handles building the widget in response to new states. BlocBuilder is very similar to StreamBuilder but has a more simple API to reduce the amount of boilerplate code needed.

BlocBuilder(
  bloc: BlocA(),
  builder: (context, state) {
    // return widget here based on BlocA's state
  }
)

BlocProvider is a Flutter widget which provides a bloc to its children via BlocProvider.of<T>(context). It is used as a DI widget so that a single instance of a bloc can be provided to multiple widgets within a subtree.

BlocProvider(
  bloc: BlocA(),
  child: ChildA(),
);

then from ChildA we can retrieve BlocA with:

BlocProvider.of<BlocA>(context)

BlocProviderTree is a Flutter widget that merges multiple BlocProvider widgets into one. BlocProviderTree improves the readability and eliminates the need to nest multiple BlocProviders. By using BlocProviderTree we can go from:

BlocProvider<BlocA>(
   bloc: BlocA(),
   child: BlocProvider<BlocB>(
     bloc: BlocB(),
     child: BlocProvider<BlocC>(
       value: BlocC(),
       child: ChildA(),
     )
   )
 )

to:

BlocProviderTree(
  blocProviders: [
    BlocProvider<BlocA>(bloc: BlocA()),
    BlocProvider<BlocB>(bloc: BlocB()),
    BlocProvider<BlocC>(bloc: BlocC()),
  ],
  child: ChildA(),
)

Usage

Lets take a look at how to use BlocBuilder to hook up a CounterPage widget to a CounterBloc.

counter_bloc.dart

enum CounterEvent { increment, decrement }

class CounterBloc extends Bloc<CounterEvent, int> {
  @override
  int get initialState => 0;

  @override
  Stream<int> mapEventToState(int currentState, CounterEvent event) async* {
    switch (event) {
      case CounterEvent.decrement:
        yield currentState - 1;
        break;
      case CounterEvent.increment:
        yield currentState + 1;
        break;
    }
  }
}

counter_page.dart

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final CounterBloc _counterBloc = BlocProvider.of<CounterBloc>(context);

    return Scaffold(
      appBar: AppBar(title: Text('Counter')),
      body: BlocBuilder<CounterEvent, int>(
        bloc: _counterBloc,
        builder: (BuildContext context, int count) {
          return Center(
            child: Text(
              '$count',
              style: TextStyle(fontSize: 24.0),
            ),
          );
        },
      ),
      floatingActionButton: Column(
        crossAxisAlignment: CrossAxisAlignment.end,
        mainAxisAlignment: MainAxisAlignment.end,
        children: <Widget>[
          Padding(
            padding: EdgeInsets.symmetric(vertical: 5.0),
            child: FloatingActionButton(
              child: Icon(Icons.add),
              onPressed: () {
                _counterBloc.dispatch(CounterEvent.increment);
              },
            ),
          ),
          Padding(
            padding: EdgeInsets.symmetric(vertical: 5.0),
            child: FloatingActionButton(
              child: Icon(Icons.remove),
              onPressed: () {
                _counterBloc.dispatch(CounterEvent.decrement);
              },
            ),
          ),
        ],
      ),
    );
  }
}

At this point we have successfully separated our presentational layer from our business logic layer. Notice that the CounterPage widget knows nothing about what happens when a user taps the buttons. The widget simply tells the CounterBloc that the user has pressed either the increment or decrement button.

Dart Versions

  • Dart 2: >= 2.0.0

Examples

  • Counter - an example of how to create a CounterBloc to implement the classic Flutter Counter app.
  • Infinite List - an example of how to use the bloc and flutter_bloc packages to implement an infinite scrolling list.
  • Login Flow - an example of how to use the bloc and flutter_bloc packages to implement a Login Flow.
  • Github Search - an example of how to create a Github Search Application using the bloc and flutter_bloc packages.
  • Weather - an example of how to create a Weather Application using the bloc and flutter_bloc packages. The app uses a RefreshIndicator to implement "pull-to-refresh" as well as dynamic theming.
  • Todos - an example of how to create a Todos Application using the bloc and flutter_bloc packages.

Maintainers

Libraries

flutter_bloc