Flutter-BLoC-第三讲

本篇已同步到 我的博客 ,欢迎常来。git

[TOC]github

本文为 《Flutter Bloc Package》 的译文,原文地址,若转载本译文请注明出处。设计模式

image.png

在使用Flutter工做一段时间以后,我决定建立一个软件包以帮助我常常使用的东西:BLoC模式。 对于那些不熟悉BLoC模式的人来讲,它是一种设计模式,有助于将表示层与业务逻辑分开。你在这里了解更多。app

使用BLoC模式可能具备挑战性,由于须要创建对Streams和Reactive Programming的理解。但它的核心是BLoC很是简单:less

BLoC 将event流做为输入,并将它们转换为state流做为输出。async

image.png

咱们如今能够在bloc的dart包的帮助下使用这种强大的设计模式。ide

该软件包抽象了模式的反应方面,容许开发人员专一于将事件(event)转换为状态(state)。函数

让咱们从定义这些术语开始......ui

词汇表

Events

Events 是Bloc的输入。它们一般是UI事件,例如按钮按下。Events被分发(dispatched)而且被转换为States。spa

States

States 是Bloc的输出。表示组件能够监听状态流 并根据给定状态重绘其自身的部分(BlocBuilder有关详细信息,请参阅参考资料)。

Transitions

Transitions 发生在 调用mapEventToState以后 但在更新了bloc的state以前 调度了一个Event

如今咱们了解事件和状态,咱们能够看一下Bloc API。

BLOC API

mapEventToState

当一个类继承Bloc时,必须实现 mapEventToState 方法, 该函数将传入事件做为参数。 只要UI层触发一个事件,就会调用 mapEventToState。 mapEventToState 必须将该event转换为新state,并以UI层使用的Stream形式返回新状态。

dispatch

dispatch 是一个 接受 event 并触发 mapEventToState 的方法。 能够从表示层调用dispatch 或 从Bloc内部(见例子)并通知Bloc一个新 event。

initialState

initialState是处理任何事件以前的状态(在mapEventToState被调用以前)。 若是未实现,则为initialState null。

transform

transform是一个 在调用mapEventToState以前 能够重写以转换 Stream . 这容许使用distinct() 和 debounce() 的操做。

onTransition

onTransition 是一个 每次 transform 发生时均可以重写以进行处理 的方法。 调度新event 并调用mapEventToState时发生transition。 onTransition 在更新 bloc 状态以前 被调用。 这是添加特定于块的日志记录/分析的好地方

让咱们建立一个counter bloc!

enum CounterEvent { increment, decrement }

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

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

建立一个BLoC 须要做以下操做:

  • 定义全部 event 和 state
  • 继承Bloc
  • 重写 initialState 和 mapEventToState

在这种状况下,咱们的 events 是CounterEvents ,states 是 integers

CounterBloc 转换 CounterEvents 为 integers。

咱们能够经过 dispatch 来 通知CounterBloc 事件

void main() {
  final counterBloc = CounterBloc();

  counterBloc.dispatch(CounterEvent.increment);
  counterBloc.dispatch(CounterEvent.decrement);
}
复制代码

为了观察状state 的 转换(Transitions),咱们能够重写onTransition。

enum CounterEvent { increment, decrement }

class CounterBloc extends Bloc<CounterEvent, int> {
  @override
  int get initialState => 0;
  
  @override
  void onTransition(Transition<CounterEvent, int> transition) {
    print(transition);
  }

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

如今,每当发出(dispatch)一个CounterEvent咱们的Bloc将响应一个新的integer状态,咱们将看到一个transition被输出到控制台。

如今让咱们使用Flutter构建一个UI,并使用flutter_bloc 包将UI链接到咱们的CounterBloc。

BlocBuilder

BlocBuilder是一个Flutter小部件,它须要一个Bloc和一个构建器函数。 BlocBuilder处理构建窗口小部件以响应新state。 BlocBuilder与StreamBuilder很是类似,但它有一个更简单的API来减小所需的样板代码量。

BlocProvider

BlocProvider是一个Flutter小部件,它经过 BlocProvider.of(context)为其子女提供了一个bloc。 它用做依赖注入(DI)小部件, 这样一个bloc实例 能够被提供给子树中的多个小部件。

如今让咱们构建 counter App

class App extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _AppState();
}

class _AppState extends State<App> {
  final CounterBloc _counterBloc = CounterBloc();

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: BlocProvider<CounterBloc>(
        bloc: _counterBloc,
        child: CounterPage(),
      ),
    );
  }

  @override
  void dispose() {
    _counterBloc.dispose();
    super.dispose();
  }
}

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);
              },
            ),
          ),
        ],
      ),
    );
  }
}
复制代码

该App小部件是StatefulWidget,负责建立和销毁 CounterBloc。 它让 CounterBloc 使用 BlocProvider 小部件可用于 CounterPage 小部件。

CounterPage小部件是StatelessWidget, 它使用BlocBuilder重建UI以响应CounterBloc的状态变化。

此时,咱们已经成功地将咱们的表示层与业务逻辑层分开。请注意,CounterPage窗口小部件对用户点击按钮时发生的状况一无所知。小部件只是告诉CounterBloc用户按下了递增或递减按钮。

有关更多示例和详细文档,请查看官方集团文档

相关连接:

bloc dart包

flutter_bloc包

flutter_bloc使用官方文档

相关文章
相关标签/搜索