Flutter状态管理架构插件ilgiz_bloc的使用
Flutter状态管理架构插件ilgiz_bloc的使用
使用 #
让我们看看如何使用BlocProvider
为CounterPage
提供一个CounterCubit
,并通过BlocBuilder
响应状态变化。
counter_cubit.dart #
class CounterCubit extends Cubit<int> {
CounterCubit() : super(0);
void increment() => emit(state + 1);
void decrement() => emit(state - 1);
}
main.dart #
void main() => runApp(CounterApp());
class CounterApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: BlocProvider(
create: (_) => CounterCubit(),
child: CounterPage(),
),
);
}
}
counter_page.dart #
class CounterPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: BlocBuilder<CounterCubit, int>(
builder: (context, count) => Center(child: Text('$count')),
),
floatingActionButton: Column(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () => context.read<CounterCubit>().increment(),
),
const SizedBox(height: 4),
FloatingActionButton(
child: const Icon(Icons.remove),
onPressed: () => context.read<CounterCubit>().decrement(),
),
],
),
);
}
}
此时,我们已经成功将展示层与业务逻辑层分离。注意CounterPage
小部件对用户点击按钮时发生的情况一无所知。该小部件只是通知CounterCubit
用户按下了增加或减少按钮。
Bloc Widgets #
BlocBuilder #
BlocBuilder 是一个 Flutter 小部件,它需要一个bloc
和一个builder
函数。BlocBuilder
会根据新的状态构建小部件。BlocBuilder
类似于StreamBuilder
,但具有更简单的 API 来减少样板代码的数量。builder
函数可能会被调用多次,并且应该是一个纯函数,根据状态返回一个 widget。
如果需要在状态变化时执行某些操作(如导航、显示对话框等),请查看BlocListener
。
如果省略了bloc
参数,BlocBuilder
将自动通过BlocProvider
和当前的BuildContext
进行查找。
BlocBuilder<BlocA, BlocAState>(
builder: (context, state) {
// 根据 BlocA 的状态返回小部件
}
)
仅当需要提供一个作用域限于单个小部件且无法通过父级BlocProvider
和当前BuildContext
访问的小部件时,才指定bloc
。
BlocBuilder<BlocA, BlocAState>(
bloc: blocA, // 提供本地 bloc 实例
builder: (context, state) {
// 根据 BlocA 的状态返回小部件
}
)
为了对builder
函数的调用进行细粒度控制,可以提供可选的buildWhen
。buildWhen
接受前一个 bloc 状态和当前 bloc 状态并返回一个布尔值。如果buildWhen
返回true
,则builder
将被调用并重新构建小部件;如果返回false
,则不会调用builder
,也不会重新构建小部件。
BlocBuilder<BlocA, BlocAState>(
buildWhen: (previousState, state) {
// 返回 true/false 以确定是否要基于状态重新构建小部件
},
builder: (context, state) {
// 根据 BlocA 的状态返回小部件
}
)
BlocSelector #
BlocSelector 是一个 Flutter 小部件,类似于BlocBuilder
,但它允许开发者通过选择基于当前 bloc 状态的新值来过滤更新。如果所选值未发生变化,则可以防止不必要的构建。所选值必须是不可变的,以便BlocSelector
能够准确地确定是否应再次调用builder
。
如果省略了bloc
参数,BlocSelector
将自动通过BlocProvider
和当前的BuildContext
进行查找。
BlocSelector<BlocA, BlocAState, SelectedState>(
selector: (state) {
// 基于提供的状态返回所选状态。
},
builder: (context, state) {
// 基于所选状态返回小部件。
},
)
BlocProvider #
BlocProvider 是一个 Flutter 小部件,通过BlocProvider.of<T>(context)
向其子项提供 bloc。它是作为依赖注入 (DI) 小部件使用的,以便为子树中的多个小部件提供单个 bloc 实例。
在大多数情况下,应该使用BlocProvider
创建新的 bloc,这些 bloc 将可供子树中的其他部分使用。在这种情况下,由于BlocProvider
负责创建 bloc,因此它将自动处理关闭。
BlocProvider(
create: (BuildContext context) => BlocA(),
child: ChildA(),
);
默认情况下,BlocProvider
会懒加载 bloc,这意味着当通过BlocProvider.of<BlocA>(context)
查找 bloc 时,才会执行create
。
若要覆盖此行为并强制立即运行create
,可以将lazy
设置为false
。
BlocProvider(
lazy: false,
create: (BuildContext context) => BlocA(),
child: ChildA(),
);
在某些情况下,可以使用BlocProvider
向新的 widget 树部分提供现有的 bloc。这通常用于将现有 bloc 提供给新路由。在这种情况下,由于BlocProvider
没有创建 bloc,因此不会自动关闭 bloc。
BlocProvider.value(
value: BlocProvider.of<BlocA>(context),
child: ScreenA(),
);
然后可以从ChildA
或ScreenA
检索BlocA
:
// 使用扩展
context.read<BlocA>();
// 不使用扩展
BlocProvider.of<BlocA>(context);
上述片段导致一次查找,小部件不会收到更改的通知。要检索实例并订阅后续状态更改,请使用:
// 使用扩展
context.watch<BlocA>();
// 不使用扩展
BlocProvider.of<BlocA>(context, listen: true);
此外,还可以使用context.select
来检索状态的一部分,并仅在所选部分发生变化时作出反应。
final isPositive = context.select((CounterBloc b) => b.state >= 0);
上述代码只有在CounterBloc
的状态从正变为负或反之时才会重建,并且功能上等同于使用BlocSelector
。
MultiBlocProvider #
MultiBlocProvider 是一个 Flutter 小部件,它可以将多个BlocProvider
小部件合并为一个。
MultiBlocProvider
提高了可读性,并消除了嵌套多个BlocProvider
的需要。
通过使用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 #
BlocListener 是一个 Flutter 小部件,它接受一个BlocWidgetListener
和一个可选的bloc
,并在 bloc 的状态变化时调用listener
。它应该用于需要在每次状态变化时发生的功能,例如导航、显示SnackBar
、显示Dialog
等。
listener
对于每个状态变化只调用一次(不包括初始状态),不像BlocBuilder
中的builder
,并且是一个void
函数。
如果省略了bloc
参数,BlocListener
将自动通过BlocProvider
和当前的BuildContext
进行查找。
BlocListener<BlocA, BlocAState>(
listener: (context, state) {
// 基于 BlocA 的状态执行操作
},
child: Container(),
)
仅当需要提供一个无法通过BlocProvider
和当前BuildContext
访问的 bloc 时,才指定bloc
。
BlocListener<BlocA, BlocAState>(
bloc: blocA,
listener: (context, state) {
// 基于 BlocA 的状态执行操作
}
)
为了对listener
函数的调用进行细粒度控制,可以提供可选的listenWhen
。listenWhen
接受前一个 bloc 状态和当前 bloc 状态并返回一个布尔值。如果listenWhen
返回true
,则listener
将被调用;如果返回false
,则不会调用listener
。
BlocListener<BlocA, BlocAState>(
listenWhen: (previousState, state) {
// 返回 true/false 以确定是否调用 listener
},
listener: (context, state) {
// 基于 BlocA 的状态执行操作
},
child: Container(),
)
MultiBlocListener #
MultiBlocListener 是一个 Flutter 小部件,它可以将多个BlocListener
小部件合并为一个。
MultiBlocListener
提高了可读性,并消除了嵌套多个BlocListener
的需要。
通过使用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 #
BlocConsumer 暴露了builder
和listener
,以便响应新的状态。BlocConsumer
类似于嵌套的BlocListener
和BlocBuilder
,但减少了样板代码的数量。BlocConsumer
应该只在需要同时重建 UI 并对 bloc 的状态变化执行其他反应时使用。BlocConsumer
需要一个必需的BlocWidgetBuilder
和BlocWidgetListener
,以及可选的bloc
、BlocBuilderCondition
和BlocListenerCondition
。
如果省略了bloc
参数,BlocConsumer
将自动通过BlocProvider
和当前的BuildContext
进行查找。
BlocConsumer<BlocA, BlocAState>(
listener: (context, state) {
// 基于 BlocA 的状态执行操作
},
builder: (context, state) {
// 根据 BlocA 的状态返回小部件
}
)
可以实现可选的listenWhen
和buildWhen
来进行更精细的控制,以决定何时调用listener
和builder
。listenWhen
和buildWhen
将在每次bloc
状态变化时被调用。它们各自接受前一个state
和当前state
,并必须返回一个bool
,以确定是否调用builder
和/或listener
函数。前一个state
将在BlocConsumer
初始化时设置为bloc
的当前state
。listenWhen
和buildWhen
是可选的,如果没有实现,它们将默认为true
。
BlocConsumer<BlocA, BlocAState>(
listenWhen: (previous, current) {
// 返回 true/false 以确定是否调用 listener
},
listener: (context, state) {
// 基于 BlocA 的状态执行操作
},
buildWhen: (previous, current) {
// 返回 true/false 以确定是否重建小部件
},
builder: (context, state) {
// 根据 BlocA 的状态返回小部件
}
)
RepositoryProvider #
RepositoryProvider 是一个 Flutter 小部件,它通过RepositoryProvider.of<T>(context)
向其子项提供 repository。它是作为依赖注入 (DI) 小部件使用的,以便为子树中的多个小部件提供单个 repository 实例。BlocProvider
应该用于提供 bloc,而RepositoryProvider
应该仅用于 repository。
RepositoryProvider(
create: (context) => RepositoryA(),
child: ChildA(),
);
然后可以从ChildA
检索Repository
实例:
// 使用扩展
context.read<RepositoryA>();
// 不使用扩展
RepositoryProvider.of<RepositoryA>(context)
MultiRepositoryProvider #
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(),
)
更多关于Flutter状态管理架构插件ilgiz_bloc的使用的实战教程也可以访问 https://www.itying.com/category-92-b0.html
更多关于Flutter状态管理架构插件ilgiz_bloc的使用的实战系列教程也可以访问 https://www.itying.com/category-92-b0.html
ilgiz_bloc
是一个基于 flutter_bloc
的状态管理插件,旨在简化 Bloc 模式的使用并提供更简洁的 API。以下是如何使用 ilgiz_bloc
的基本指南。
1. 添加依赖
首先,在 pubspec.yaml
文件中添加 ilgiz_bloc
依赖:
dependencies:
flutter:
sdk: flutter
ilgiz_bloc: ^1.0.0 # 请使用最新版本
然后运行 flutter pub get
来安装依赖。
2. 创建 Bloc
使用 ilgiz_bloc
创建 Bloc 非常简单。以下是一个简单的计数器示例:
import 'package:ilgiz_bloc/ilgiz_bloc.dart';
class CounterBloc extends Bloc<CounterEvent, int> {
CounterBloc() : super(0);
[@override](/user/override)
Stream<int> mapEventToState(CounterEvent event) async* {
if (event is IncrementEvent) {
yield state + 1;
} else if (event is DecrementEvent) {
yield state - 1;
}
}
}
abstract class CounterEvent {}
class IncrementEvent extends CounterEvent {}
class DecrementEvent extends CounterEvent {}
3. 使用 BlocBuilder 和 BlocProvider
在 Flutter 应用中使用 BlocProvider
和 BlocBuilder
来管理状态:
import 'package:flutter/material.dart';
import 'package:ilgiz_bloc/ilgiz_bloc.dart';
import 'counter_bloc.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
return MaterialApp(
home: BlocProvider(
create: (context) => CounterBloc(),
child: CounterPage(),
),
);
}
}
class CounterPage extends StatelessWidget {
[@override](/user/override)
Widget build(BuildContext context) {
final CounterBloc counterBloc = BlocProvider.of<CounterBloc>(context);
return Scaffold(
appBar: AppBar(title: Text('Counter App')),
body: Center(
child: BlocBuilder<CounterBloc, int>(
builder: (context, count) {
return Text('Count: $count', style: TextStyle(fontSize: 24));
},
),
),
floatingActionButton: Column(
mainAxisAlignment: MainAxisAlignment.end,
children: [
FloatingActionButton(
onPressed: () => counterBloc.add(IncrementEvent()),
child: Icon(Icons.add),
),
SizedBox(height: 10),
FloatingActionButton(
onPressed: () => counterBloc.add(DecrementEvent()),
child: Icon(Icons.remove),
),
],
),
);
}
}