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使用官方文檔

相關文章
相關標籤/搜索