闽公网安备 35020302035485号
typedef StateBuilder<T> = Widget Function(T state);比如显示计数器的 Text,我们可以这么写:
SimpleBlocProvider<int> (
builder: (count) => Text('$count'),
)
光有 builder 还不够,我们需要 Bloc 逻辑组件,以便从逻辑组件里获取最新的状态数据,因此需要将 Bloc 逻辑组件也作为参数给 SimpleBlocProvider。于是我们就得到了SimpleBlocProvider的基本定义了。class SimpleBlocProvider<T> extends StatefulWidget {
final StateBuilder<T> builder;
final BlocBase<T> bloc;
const SimpleBlocProvider(
{Key? key, required this.builder, required this.bloc})
: super(key: key);
@override
_SimpleBlocProviderState<T> createState() => _SimpleBlocProviderState<T>();
}
StreamSubscription<T> listen(void onData(T event)?,
{Function? onError, void onDone()?, bool? cancelOnError});
因此,我们可以在 listen 的 onData 中调用 setState 就可以做到刷新界面了。我们组件销毁的时候需要取消监听,因此我们在_SimpleBlocProviderState 中定义一个属性_streamSubscription存储 listen 方法的返回值,并在 dispose 中取消监听。_streamSubscription = widget.bloc.stream.listen((data) {
setState(() {
_state = data;
});
});
//
@override
void dispose() {
_streamSubscription.cancel();
super.dispose();
}
接下来就比较简单了,在_SimpleBlocProviderState的 build 方法中直接返回 builder 携带状态数据_state构建组件即可。@override
Widget build(BuildContext context) {
return widget.builder(_state);
}
这样,只要 BLoC 的状态数据发生了改变,就会通过 listen监听更新SimpleBlocProvider的_state,并刷新SimpleBlocProvider组件,从而更新了 builder 构建的组件。完整代码如下:typedef StateBuilder<T> = Widget Function(T state);
// 堆代码 duidaima.com
class SimpleBlocProvider<T> extends StatefulWidget {
final StateBuilder<T> builder;
final BlocBase<T> bloc;
const SimpleBlocProvider(
{Key? key, required this.builder, required this.bloc})
: super(key: key);
@override
_SimpleBlocProviderState<T> createState() => _SimpleBlocProviderState<T>();
}
class _SimpleBlocProviderState<T> extends State<SimpleBlocProvider<T>> {
late T _state;
late StreamSubscription<T> _streamSubscription;
@override
void initState() {
_state = widget.bloc.state;
super.initState();
_streamSubscription = widget.bloc.stream.listen((data) {
setState(() {
_state = data;
});
});
}
@override
Widget build(BuildContext context) {
return widget.builder(_state);
}
@override
void dispose() {
_streamSubscription.cancel();
super.dispose();
}
}
总共不到 40 行代码就搞定了!class CounterCubit extends Cubit<int> {
CounterCubit({initial = 0}) : super(initial);
void increment() => emit(state + 1);
void decrement() => emit(state - 1);
@override
void onChange(Change<int> change) {
super.onChange(change);
}
}
class SimpleBlocCounterPage extends StatelessWidget {
final counter = CounterCubit();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Bloc 计数器'),
),
body: Center(
child: SimpleBlocProvider<int>(
builder: (count) => Text(
'$count',
style: TextStyle(
fontSize: 32,
color: Colors.blue,
),
),
bloc: counter,
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
counter.increment();
},
tooltip: '点击增加',
child: Icon(Icons.add),
),
);
}
}
是不是和我们之前在使用 MobX,GetX 的 GetBuilder 很类似?再来看自定义类,来个简单的 Person 类,然后用 Bloc 的 event 模式试试。
// 堆代码 duidaima.com
class Person {
final String name;
final String gender;
const Person({required this.name, required this.gender});
}
abstract class PersonEvent {}
class UsingCnNameEvent extends PersonEvent {}
class UsingEnNameEvent extends PersonEvent {}
class PersonBloc extends Bloc<PersonEvent, Person> {
PersonBloc(Person person) : super(person) {
on<UsingCnNameEvent>(
(event, emit) => emit(Person(name: '岛上码农', gender: '男')));
on<UsingEnNameEvent>(
(event, emit) => emit(Person(name: 'island-coder', gender: 'male')));
}
}
class SimpleBlocCounterPage extends StatelessWidget {
final personBloc = PersonBloc(Person(name: '岛上码农', gender: '男'));
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Bloc 事件'),
),
body: Center(
child: SimpleBlocProvider<Person>(
builder: (person) => Text(
'姓名:${person.name},性别:${person.gender}',
style: TextStyle(
fontSize: 22,
color: Colors.blue,
),
),
bloc: personBloc,
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
personBloc.add(UsingEnNameEvent());
},
tooltip: '点击增加',
child: Icon(Icons.add),
),
);
}
}
运行起来也是没问题的。