flutter_bloc使用将从下图的三个维度说明
项目效果(建议PC浏览器打开)
初次使用flutter_bloc框架,可能会有几个疑问
说明
BlocBuilder
放在顶层,因为本身页面非常简单,也是为了更好呈现页面结构,所以才放在顶层,如果需要更加颗粒化控件更新区域,请将BlocBuilder
包裹你需要更新的控件区域即可引用
库
flutter_bloc: ^6.1.1 #状态管理框架
equatable: ^1.2.3 #增强组件相等性判断
插件
在Android Studio设置的Plugins里,搜索:Bloc
安装重启下,就OK了
来看下这三个生成的bloc文件:main_bloc,main_event,main_state
class MainBloc extends Bloc<MainEvent, MainState> {
MainBloc() : super(MainInitial());
@override
Stream<MainState> mapEventToState(
MainEvent event,
) async* {
// TODO: implement mapEventToState
}
}
@immutable
abstract class MainEvent {}
@immutable
abstract class MainState {}
class MainInitial extends MainState {}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MainPage(),
);
}
}
class MainBloc extends Bloc<MainEvent, MainState> {
MainBloc() : super(MainState(selectedIndex: 0, isExtended: false));
@override
Stream<MainState> mapEventToState(MainEvent event) async* {
///main_view中添加的事件,会在此处回调,此处处理完数据,将数据yield,BlocBuilder就会刷新组件
if (event is SwitchTabEvent) {
///获取到event事件传递过来的值,咱们拿到这值塞进MainState中
///直接在state上改变内部的值,然后yield,只能触发一次BlocBuilder,它内部会比较上次MainState对象,如果相同,就不build
yield MainState()
..selectedIndex = event.selectedIndex
..isExtended = state.isExtended;
} else if (event is IsExtendEvent) {
yield MainState()
..selectedIndex = state.selectedIndex
..isExtended = !state.isExtended;
}
}
}
@immutable
abstract class MainEvent extends Equatable{
const MainEvent();
}
///切换NavigationRail的tab
class SwitchTabEvent extends MainEvent{
final int selectedIndex;
const SwitchTabEvent({@required this.selectedIndex});
@override
List<Object> get props => [selectedIndex];
}
///展开NavigationRail,这个逻辑比较简单,就不用传参数了
class IsExtendEvent extends MainEvent{
const IsExtendEvent();
@override
List<Object> get props => [];
}
class MainState{
int selectedIndex;
bool isExtended;
MainState({this.selectedIndex, this.isExtended});
}
class MainPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return _buildBg(children: [
//侧边栏
_buildLeftNavigation(),
//右边主体内容
Expanded(child: Center(
child: BlocBuilder<MainBloc, MainState>(builder: (context, state) {
return Text(
"选择Index:" + state.selectedIndex.toString(),
style: TextStyle(fontSize: 30.0),
);
}),
))
]);
}
Widget _buildBg({List<Widget> children}) {
///创建BlocProvider的,表明该Page,我们是用MainBloc,MainBloc是属于该页面的Bloc了
return BlocProvider(
create: (BuildContext context) => MainBloc(),
child: Scaffold(
appBar: AppBar(title: Text('Bloc')),
body: Row(children: children),
),
);
}
//增加NavigationRail组件为侧边栏
Widget _buildLeftNavigation() {
return BlocBuilder<MainBloc, MainState>(builder: (context, state) {
return NavigationRail(
backgroundColor: Colors.white,
elevation: 3,
extended: state.isExtended,
labelType: state.isExtended
? NavigationRailLabelType.none
: NavigationRailLabelType.selected,
//侧边栏中的item
destinations: [
NavigationRailDestination(
icon: Icon(Icons.add_to_queue),
selectedIcon: Icon(Icons.add_to_photos),
label: Text("测试一"),
),
NavigationRailDestination(
icon: Icon(Icons.add_circle_outline),
selectedIcon: Icon(Icons.add_circle),
label: Text("测试二"),
),
NavigationRailDestination(
icon: Icon(Icons.bubble_chart),
selectedIcon: Icon(Icons.broken_image),
label: Text("测试三"),
),
],
//顶部widget
leading: _buildNavigationTop(),
//底部widget
trailing: _buildNavigationBottom(),
selectedIndex: state.selectedIndex,
onDestinationSelected: (int index) {
///添加切换tab事件
BlocProvider.of<MainBloc>(context)
.add(SwitchTabEvent(selectedIndex: index));
},
);
});
}
Widget _buildNavigationTop() {
return Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
width: 80,
height: 80,
decoration: BoxDecoration(
shape: BoxShape.circle,
image: DecorationImage(
image: NetworkImage(
"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3383029432,2292503864&fm=26&gp=0.jpg",
),
fit: BoxFit.fill,
),
),
),
),
);
}
Widget _buildNavigationBottom() {
return Container(
child: BlocBuilder<MainBloc, MainState>(
builder: (context, state) {
return FloatingActionButton(
onPressed: () {
///添加NavigationRail展开,收缩事件
BlocProvider.of<MainBloc>(context).add(IsExtendEvent());
},
child: Icon(state.isExtended ? Icons.send : Icons.navigation),
);
},
),
);
}
}
从上面的代码来看,实际存在几个隐式问题,这些问题,刚开始使用时候,没异常的感觉,但是使用bloc久了后,感觉肯定越来越强烈
因为官方插件生成的写法,和调整后写法差距有点大,而且官方插件不支持生成view层和相关设置,此处我就撸了一个插件,完善了相关功能
请注意,wrap代码和提示代码片段,参靠了官方插件规则
Wrap Widget 规则来着:intellij_generator_plugin
快捷代码生成规则来着: intellij_generator_plugin
这边完整走一下流程,让大家能有个完整的思路
class MainState {
int selectedIndex;
bool isExtended;
///初始化方法,基础变量也需要赋初值,不然会报空异常
MainState init() {
return MainState()
..selectedIndex = 0
..isExtended = false;
}
///clone方法,此方法实现参考fish_redux的clone方法
///也是对官方Flutter Login Tutorial这个demo中copyWith方法的一个优化
///Flutter Login Tutorial(https://bloclibrary.dev/#/flutterlogintutorial)
MainState clone() {
return MainState()
..selectedIndex = selectedIndex
..isExtended = isExtended;
}
}
@immutable
abstract class MainEvent {}
///初始化事件,这边目前不需要传什么值
class MainInitEvent extends MainEvent {}
///切换NavigationRail的tab
class SwitchTabEvent extends MainEvent {
final int selectedIndex;
SwitchTabEvent({@required this.selectedIndex});
}
///展开NavigationRail,这个逻辑比较简单,就不用传参数了
class IsExtendEvent extends MainEvent {}
class MainBloc extends Bloc<MainEvent, MainState> {
MainBloc() : super(MainState().init());
@override
Stream<MainState> mapEventToState(MainEvent event) async* {
///main_view中添加的事件,会在此处回调,此处处理完数据,将数据yield,BlocBuilder就会刷新组件
if (event is MainInitEvent) {
yield await init();
} else if (event is SwitchTabEvent) {
///获取到event事件传递过来的值,咱们拿到这值塞进MainState中
///直接在state上改变内部的值,然后yield,只能触发一次BlocBuilder,它内部会比较上次MainState对象,如果相同,就不build
yield switchTap(event);
} else if (event is IsExtendEvent) {
yield isExtend();
}
}
///初始化操作,在网络请求的情况下,需要使用如此方法同步数据
Future<MainState> init() async {
return state.clone();
}
///切换tab
MainState switchTap(SwitchTabEvent event) {
return state.clone()..selectedIndex = event.selectedIndex;
}
///是否展开
MainState isExtend() {
return state.clone()..isExtended = !state.isExtended;
}
}
class MainPage extends StatelessWidget {
...
Widget _buildBg({List<Widget> children}) {
///创建BlocProvider的,表明该Page,我们是用MainBloc,MainBloc是属于该页面的Bloc了
return BlocProvider(
create: (BuildContext context) => MainBloc()..add(MainInitEvent()),
child: Scaffold(
appBar: AppBar(title: Text('Bloc')),
body: Row(children: children),
),
);
}
///下方其余代码省略...........
}
bloc8.0+的版本,对比之前的写法简直是破坏式的改变,你如果升级到bloc 8.0及其以上的版本,之前写的bloc模式写法已经完全不兼容了,mapEventToState
方法直接被移除了,一运行项目,bloc内部也会给出报错,需要你手动去注册处理器
有一说一,虽然是破坏式的改变写法,但是新写法是非常的优雅,彻底改变了以前的mapEventToState
方法中的各种判断Event
这种彻底不兼容的做法,确实非常的激进,但是为了优化的点,亦有可圈可点之处
来看下版本生成代码
class TestPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => TestBloc()..add(InitEvent()),
child: Builder(builder: (context) => _buildPage(context)),
);
}
Widget _buildPage(BuildContext context) {
final bloc = BlocProvider.of<TestBloc>(context);
return Container();
}
}
class TestBloc extends Bloc<TestEvent, TestState> {
TestBloc() : super(TestState().init()) {
on<InitEvent>(_init);
}
void _init(InitEvent event, Emitter<TestState> emit) async {
emit(state.clone());
}
}
class TestState {
TestState init() {
return TestState();
}
TestState clone() {
return TestState();
}
}
abstract class TestEvent {}
class InitEvent extends TestEvent {}
可以发现Bloc层,完全不用写判断了
计数器实例
写个计数器demo,大家来感受下
class BlBlocCounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => BlBlocCounterBloc()..add(InitEvent()),
child: Builder(builder: (context) => _buildPage(context)),
);
}
Widget _buildPage(BuildContext context) {
final bloc = BlocProvider.of<BlBlocCounterBloc>(context);
return Scaffold(
appBar: AppBar(title: Text('Bloc-Bloc范例')),
body: Center(
child: BlocBuilder<BlBlocCounterBloc, BlBlocCounterState>(
builder: (context, state) {
return Text(
'点击了 ${bloc.state.count} 次',
style: TextStyle(fontSize: 30.0),
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => bloc.add(CounterIncrementEvent()),
child: Icon(Icons.add),
),
);
}
}
class BlBlocCounterBloc extends Bloc<BlBlocCounterEvent, BlBlocCounterState> {
BlBlocCounterBloc() : super(BlBlocCounterState().init()) {
//页面初始化时刻
on<InitEvent>(_init);
//计数器自增
on<CounterIncrementEvent>(_increment);
}
void _init(InitEvent event, Emitter<BlBlocCounterState> emit) async {
//处理一些初始化操作,然后刷新界面
emit(state.clone());
}
///自增
void _increment(
CounterIncrementEvent event,
Emitter<BlBlocCounterState> emit,
) {
state.count++;
emit(state.clone());
}
}
class BlBlocCounterState {
late int count;
BlBlocCounterState init() {
return BlBlocCounterState()..count = 0;
}
BlBlocCounterState clone() {
return BlBlocCounterState()..count = count;
}
}
abstract class BlBlocCounterEvent {}
class InitEvent extends BlBlocCounterEvent {}
class CounterIncrementEvent extends BlBlocCounterEvent {}
新写法,对Bloc层改动是巨大的
可以发现,主要改变的就是对事件的处理;改动后写法对比以前的写法,优雅了N倍
bloc层的新写法确实不错,新项目如果用bloc,可以无脑升级bloc 8.0,使用这种新写法;老项目页面多的话,改动起来,成本确实非常的大,大家自己抉择喽
新建好后,他会生成三个文件:cubit,state,view;来看下生成的代码
class CounterCubit extends Cubit<CounterState> {
CounterCubit() : super(CounterState().init());
}
class CounterState {
CounterState init() {
return CounterState();
}
CounterState clone() {
return CounterState();
}
}
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => CounterCubit(),
child: Builder(builder: (context) => _buildPage(context)),
);
}
Widget _buildPage(BuildContext context) {
final cubit = BlocProvider.of<CounterCubit>(context);
return Container();
}
}
效果
实现
实现很简单,三个文件就搞定,看下流程:state -> cubit -> view
class BlCubitCounterState {
late int count;
BlCubitCounterState init() {
return BlCubitCounterState()..count = 0;
}
BlCubitCounterState clone() {
return BlCubitCounterState()..count = count;
}
}
class BlCubitCounterCubit extends Cubit<BlCubitCounterState> {
BlCubitCounterCubit() : super(BlCubitCounterState().init());
///自增
void increment() => emit(state.clone()..count = ++state.count);
}
class BlCubitCounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (BuildContext context) => BlCubitCounterCubit(),
child: Builder(builder: (context) => _buildPage(context)),
);
}
Widget _buildPage(BuildContext context) {
final cubit = BlocProvider.of<BlCubitCounterCubit>(context);
return Scaffold(
appBar: AppBar(title: Text('Bloc-Cubit范例')),
body: Center(
child: BlocBuilder<BlCubitCounterCubit, BlCubitCounterState>(
builder: (context, state) {
return Text(
'点击了 ${cubit.state.count} 次',
style: TextStyle(fontSize: 30.0),
);
},
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => cubit.increment(),
child: Icon(Icons.add),
),
);
}
}
在Bloc模式里面,如果页面不是过于复杂,使用Cubit去写,基本完全够用了;但是如果业务过于复杂,还是需要用Bloc去写,需要将所有的事件行为管理起来,便于后期维护
OK,Bloc的简化模块,Cubit模式就这样讲完了,对于自己业务写的小项目,我就经常用这个Cubit去写
什么是全局Bloc?
使用场景
BlocProvider.of<XxxBloc>(context)
调用全局XxxBloc中事件,这就起到了一种跨页面调用事件的效果来看下怎么创建和使用全局Bloc吧!
MultiBlocProvider
在Builder里面套在child上面就行了;当然了,把MultiBlocProvider
套在MaterialApp上也是可以的SpanOneCubit
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: MainPage(),
builder: (BuildContext context, Widget child) {
return MultiBlocProvider(
providers: [
///此处通过BlocProvider创建的Bloc或者Cubit是全局的
BlocProvider<SpanOneCubit>(
create: (BuildContext context) => SpanOneCubit(),
),
],
child: child,
);
},
);
}
}
需要用俩个Bloc模块来演示,这里分别用SpanOneCubit
和SpanTwoCubit
来演示,其中SpanOneCubit
是全局的
SpanOneCubit
class SpanOneState {
int count;
///初始化方法
SpanOneState init() {
return SpanOneState()..count = 0;
}
///克隆方法,针对于刷新界面数据
SpanOneState clone() {
return SpanOneState()..count = count;
}
}
BlocProvider
创建了SpanOneCubit
,所以在这个页面不需要再次创建,直接使用BlocBuilder
便可以获取其state伪
)class CubitSpanOnePage extends StatefulWidget {
@override
_SpanOnePageState createState() => _SpanOnePageState();
}
class _SpanOnePageState extends State<CubitSpanOnePage> {
@override
void initState() {
BlocProvider.of<BlocSpanOneCubit>(context).init();
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(title: Text('跨页面-One')),
floatingActionButton: FloatingActionButton(
onPressed: () => BlocProvider.of<BlocSpanOneCubit>(context).toSpanTwo(context),
child: const Icon(Icons.arrow_forward_outlined),
),
body: Center(
child: BlocBuilder<BlocSpanOneCubit, BlocSpanOneState>(
builder: (context, state) {
return Text(
'SpanTwoPage点击了 ${state.count} 次',
style: TextStyle(fontSize: 30.0),
);
},
),
),
);
}
}
class SpanOneCubit extends Cubit<SpanOneState> {
SpanOneCubit() : super(SpanOneState().init());
void init() {
emit(state.init());
}
///跳转到跨页面
void toSpanTwo(BuildContext context) {
Navigator.push(context, MaterialPageRoute(builder: (context) => SpanTwoPage()));
}
///自增
void increase() {
state..count = ++state.count;
emit(state.clone());
}
}
SpanTwoCubit
class SpanTwoState {
int count;
///初始化方法
SpanTwoState init() {
return SpanTwoState()..count = 0;
}
///克隆方法,针对于刷新界面数据
SpanTwoState clone() {
return SpanTwoState()..count = count;
}
}
SpanOneCubit
中的自增方法,OK,这里我们就能同步的改变SpanOneCubit
模块的数据了!class CubitSpanTwoPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => BlocSpanTwoCubit()..init(context),
child: Builder(builder: (context) => _buildPage(context)),
);
}
Widget _buildPage(BuildContext context) {
final cubit = BlocProvider.of<BlocSpanTwoCubit>(context);
return Scaffold(
backgroundColor: Colors.white,
appBar: AppBar(title: Text('跨页面-Two')),
floatingActionButton: FloatingActionButton(
onPressed: () {
//改变SpanOneCubit模块数据
BlocProvider.of<BlocSpanOneCubit>(context).increase();
//改变当前页面数据
cubit.increase();
},
child: const Icon(Icons.add),
),
body: Center(
child: BlocBuilder<BlocSpanTwoCubit, BlocSpanTwoState>(
builder: (context, state) {
return Text('当前点击了 ${state.count} 次',
style: TextStyle(fontSize: 30.0));
},
),
),
);
}
}
class SpanTwoCubit extends Cubit<SpanTwoState> {
SpanTwoCubit() : super(SpanTwoState().init());
void init(BuildContext context){
emit(state.init());
}
///自增
void increase() => emit(state.clone()..count = ++state.count);
}
OK,这样便用全局Bloc实现了类似广播的一种效果
BlocBuilder是Flutter窗口小部件,需要Bloc
和builder
函数。BlocBuilder
处理构建小部件以响应新状态。BlocBuilder
与非常相似,StreamBuilder
但具有更简单的API,可以减少所需的样板代码量。该builder
函数可能会被多次调用,并且应该是一个纯函数,它会根据状态返回小部件。
看看BlocListener
是否要响应状态更改“执行”任何操作,例如导航,显示对话框等。
如果省略cubit参数,BlocBuilder
将使用BlocProvider
和当前函数自动执行查找BuildContext
。
BlocBuilder<BlocA, BlocAState>(
builder: (context, state) {
// return widget here based on BlocA's state
}
)
仅当您希望提供一个范围仅限于单个窗口小部件且无法通过父级BlocProvider
和当前类访问的bloc时,才指定该bloc BuildContext
。
BlocBuilder<BlocA, BlocAState>(
cubit: blocA, // provide the local cubit instance
builder: (context, state) {
// return widget here based on BlocA's state
}
)
为了对何时builder
调用该函数进行细粒度的控制,buildWhen
可以提供一个可选的选项。buildWhen
获取先前的块状态和当前的块状态并返回一个布尔值。如果buildWhen
返回true,builder
将使用进行调用,state
并且小部件将重新生成。如果buildWhen
返回false,builder
则不会调用state
且不会进行重建。
BlocBuilder<BlocA, BlocAState>(
buildWhen: (previousState, state) {
// return true/false to determine whether or not
// to rebuild the widget with state
},
builder: (context, state) {
// return widget here based on BlocA's state
}
)
BlocProvider是Flutter小部件,可通过为其子元素提供块BlocProvider.of<T>(context)
。它用作依赖项注入(DI)小部件,以便可以将一个块的单个实例提供给子树中的多个小部件。
在大多数情况下,BlocProvider
应使用它来创建新的bloc,这些bloc将可用于其余子树。在这种情况下,由于BlocProvider
负责创建块,它将自动处理关闭bloc。
BlocProvider(
create: (BuildContext context) => BlocA(),
child: ChildA(),
);
默认情况下,BlocProvider
将懒惰地创建bloc,这意味着create
当通过查找块时将执行该bloc BlocProvider.of<BlocA>(context)
。
要覆盖此行为并强制create
立即运行,lazy
可以将其设置为false
。
BlocProvider(
lazy: false,
create: (BuildContext context) => BlocA(),
child: ChildA(),
);
在某些情况下,BlocProvider
可用于向小部件树的新部分提供现有的bloc。当需要将现有bloc用于新路线时,这将是最常用的。在这种情况下,BlocProvider
由于不会创建bloc,因此不会自动关闭该bloc。
BlocProvider.value(
value: BlocProvider.of<BlocA>(context),
child: ScreenA(),
);
然后从ChildA
或ScreenA
中检索BlocA
:
// with extensions
context.read<BlocA>();
// without extensions
BlocProvider.of<BlocA>(context)复制到剪贴板错误复制的
MultiBlocProvider是Flutter小部件,可将多个BlocProvider
小部件合并为一个。 MultiBlocProvider
提高了可读性,消除了嵌套多个元素的需求BlocProviders
。通过使用,MultiBlocProvider
我们可以从:
BlocProvider<BlocA>(
create: (BuildContext context) => BlocA(),
child: BlocProvider<BlocB>(
create: (BuildContext context) => BlocB(),
child: BlocProvider<BlocC>(
create: (BuildContext context) => BlocC(),
child: ChildA(),
)
)
)
至:
MultiBlocProvider(
providers: [
BlocProvider<BlocA>(
create: (BuildContext context) => BlocA(),
),
BlocProvider<BlocB>(
create: (BuildContext context) => BlocB(),
),
BlocProvider<BlocC>(
create: (BuildContext context) => BlocC(),
),
],
child: ChildA(),
)
BlocListener是Flutter小部件,它带有BlocWidgetListener
和一个可选Bloc
,listener
以响应bloc中的状态变化。它应用于需要在每次状态更改时发生一次的功能,例如导航,显示a SnackBar
,显示aDialog
等。
listener`与in和函数不同,每次状态更改(**不**包括初始状态)仅被调用一次。`builder``BlocBuilder``void
如果省略cubit参数,BlocListener
将使用BlocProvider
和当前函数自动执行查找BuildContext
。
BlocListener<BlocA, BlocAState>(
listener: (context, state) {
// do stuff here based on BlocA's state
},
child: Container(),
)
仅当您希望提供无法通过BlocProvider
和当前访问的bloc时,才指定该bloc BuildContext
。
BlocListener<BlocA, BlocAState>(
cubit: blocA,
listener: (context, state) {
// do stuff here based on BlocA's state
},
child: Container()
)
为了对何时listener
调用该函数进行细粒度的控制,listenWhen
可以提供一个可选的选项。listenWhen
获取先前的bloc状态和当前的bloc状态并返回一个布尔值。如果listenWhen
返回true,listener
将使用调用state
。如果listenWhen
返回false,listener
则不会调用state
。
BlocListener<BlocA, BlocAState>(
listenWhen: (previousState, state) {
// return true/false to determine whether or not
// to call listener with state
},
listener: (context, state) {
// do stuff here based on BlocA's state
},
child: Container(),
)
MultiBlocListener是Flutter小部件,可将多个BlocListener
小部件合并为一个。 MultiBlocListener
提高了可读性,消除了嵌套多个元素的需求BlocListeners
。通过使用,MultiBlocListener
我们可以从:
BlocListener<BlocA, BlocAState>(
listener: (context, state) {},
child: BlocListener<BlocB, BlocBState>(
listener: (context, state) {},
child: BlocListener<BlocC, BlocCState>(
listener: (context, state) {},
child: ChildA(),
),
),
)
至:
MultiBlocListener(
listeners: [
BlocListener<BlocA, BlocAState>(
listener: (context, state) {},
),
BlocListener<BlocB, BlocBState>(
listener: (context, state) {},
),
BlocListener<BlocC, BlocCState>(
listener: (context, state) {},
),
],
child: ChildA(),
)
BlocConsumer公开builder
和listener
以便对新状态做出反应。BlocConsumer
与嵌套类似BlocListener
,BlocBuilder
但减少了所需的样板数量。BlocConsumer
仅应在需要重建UI和执行其他对状态更改进行响应的情况下使用cubit
。BlocConsumer
取需要BlocWidgetBuilder
和BlocWidgetListener
和任选的cubit
,BlocBuilderCondition
和BlocListenerCondition
。
如果cubit
省略该参数,BlocConsumer
将使用BlocProvider
和当前函数自动执行查找 BuildContext
。
BlocConsumer<BlocA, BlocAState>(
listener: (context, state) {
// do stuff here based on BlocA's state
},
builder: (context, state) {
// return widget here based on BlocA's state
}
)
可选的listenWhen
,buildWhen
可以实现,以更精细地控制何时listener
和builder
被调用。在listenWhen
和buildWhen
将在每个被调用cubit
state
的变化。它们各自采用先前的state
和当前的,state
并且必须返回a bool
,以确定是否将调用builder
and / orlistener
函数。以前state
会被初始化为state
的cubit
的时候BlocConsumer
被初始化。listenWhen
并且buildWhen
是可选的,如果未实现,则默认为true
。
BlocConsumer<BlocA, BlocAState>(
listenWhen: (previous, current) {
// return true/false to determine whether or not
// to invoke listener with state
},
listener: (context, state) {
// do stuff here based on BlocA's state
},
buildWhen: (previous, current) {
// return true/false to determine whether or not
// to rebuild the widget with state
},
builder: (context, state) {
// return widget here based on BlocA's state
}
)
RepositoryProvider是Flutter小部件,它通过为其子节点提供存储库RepositoryProvider.of<T>(context)
。它用作依赖项注入(DI)小部件,以便可以将存储库的单个实例提供给子树中的多个小部件。BlocProvider
应该用于提供块,而RepositoryProvider
只能用于存储库。
RepositoryProvider(
create: (context) => RepositoryA(),
child: ChildA(),
);
然后ChildA
我们可以通过以下方式检索Repository
实例:
// with extensions
context.read<RepositoryA>();
// without extensions
RepositoryProvider.of<RepositoryA>(context)
MultiRepositoryProvider是Flutter小部件,将多个RepositoryProvider
小部件合并为一个。 MultiRepositoryProvider
提高了可读性,消除了嵌套多个元素的需求RepositoryProvider
。通过使用,MultiRepositoryProvider
我们可以从:
RepositoryProvider<RepositoryA>(
create: (context) => RepositoryA(),
child: RepositoryProvider<RepositoryB>(
create: (context) => RepositoryB(),
child: RepositoryProvider<RepositoryC>(
create: (context) => RepositoryC(),
child: ChildA(),
)
)
)
至:
MultiRepositoryProvider(
providers: [
RepositoryProvider<RepositoryA>(
create: (context) => RepositoryA(),
),
RepositoryProvider<RepositoryB>(
create: (context) => RepositoryB(),
),
RepositoryProvider<RepositoryC>(
create: (context) => RepositoryC(),
),
],
child: ChildA(),
)
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。