本篇已同步到 我的博客 ,歡迎常來。git
[TOC]github
本文爲 《Flutter Bloc Package》 的譯文,原文地址,若轉載本譯文請註明出處。設計模式
在使用Flutter工做一段時間以後,我決定建立一個軟件包以幫助我常常使用的東西:BLoC模式。 對於那些不熟悉BLoC模式的人來講,它是一種設計模式,有助於將表示層與業務邏輯分開。你在這裏瞭解更多。app
使用BLoC模式可能具備挑戰性,由於須要創建對Streams和Reactive Programming的理解。但它的核心是BLoC很是簡單:less
BLoC 將event流做爲輸入,並將它們轉換爲state流做爲輸出。async
咱們如今能夠在bloc的dart包的幫助下使用這種強大的設計模式。ide
該軟件包抽象了模式的反應方面,容許開發人員專一於將事件(event)轉換爲狀態(state)。函數
讓咱們從定義這些術語開始......ui
Events 是Bloc的輸入。它們一般是UI事件,例如按鈕按下。Events被分發(dispatched)而且被轉換爲States。spa
States 是Bloc的輸出。表示組件能夠監聽狀態流 並根據給定狀態重繪其自身的部分(BlocBuilder有關詳細信息,請參閱參考資料)。
Transitions 發生在 調用mapEventToState以後 但在更新了bloc的state以前 調度了一個Event
如今咱們瞭解事件和狀態,咱們能夠看一下Bloc API。
當一個類繼承Bloc時,必須實現 mapEventToState 方法, 該函數將傳入事件做爲參數。 只要UI層觸發一個事件,就會調用 mapEventToState。 mapEventToState 必須將該event轉換爲新state,並以UI層使用的Stream形式返回新狀態。
dispatch 是一個 接受 event 並觸發 mapEventToState 的方法。 能夠從表示層調用dispatch 或 從Bloc內部(見例子)並通知Bloc一個新 event。
initialState是處理任何事件以前的狀態(在mapEventToState被調用以前)。 若是未實現,則爲initialState null。
transform是一個 在調用mapEventToState以前 能夠重寫以轉換 Stream . 這容許使用distinct() 和 debounce() 的操做。
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是一個Flutter小部件,它須要一個Bloc和一個構建器函數。 BlocBuilder處理構建窗口小部件以響應新state。 BlocBuilder與StreamBuilder很是類似,但它有一個更簡單的API來減小所需的樣板代碼量。
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用戶按下了遞增或遞減按鈕。
有關更多示例和詳細文檔,請查看官方集團文檔。
相關連接: