Flutter_bloc 框架使用笔记,后续估计都不太会用了
final String phone;
@override_Regi
sterPageState createState() => _RegisterPageState();}
class _RegisterPageState extends State<RegisterPage> {final _registerBloc = RegisterBloc(RegisterState());
@overrideWidget build(BuildContext context) {return Scaffold(appBar: AppBar(title: Text(LS.of(context, "register")),),body: BlocProvider<RegisterBloc>(create: (_) => _registerBloc,child: RegisterScreen(widget.phone),),);}}
作为一个主体的页面,定义了 route 名称。 可以使用StatelessWidget
。因为正常也没什么状态管理
在 state 里面的 builder 里构建了BlocProvider
,
body: BlocProvider<RegisterBloc>(create: (_) => _registerBloc,child: RegisterScreen(widget.phone),)
这里是为后续的节点注册了一个RegisterBloc
, 从这个节点下级的 widget 就可以通过Provider.of<RegisterBloc>
来获取。 当然也可以有其他的方式比如context.read<RegisterBloc>
来获取。
这里也可以把 bloc 传给 screen,可以方便在 screen 里面获取 bloc。而不是通过在配置树里查找 bloc。能稍微减少些性能消耗。
screen
screen 主要是构建配置页面内容用。
class RegisterScreen extends StatelessWidget {const RegisterScreen(this.phone, {Key? key,}) : super(key: key);
final String phone;
@overrideWidget build(BuildContext context) {return BlocListener<RegisterBloc, RegisterState>(listener: (ctx, state) {if (state.status.isSubmissionInProgress) {EasyLoading.show(maskType: EasyLoadingMaskType.clear, dismissOnTap: false);return;}if (state.status.isSubmissionFailure) {EasyLoading.dismiss();var message = LS.of(context, "register_error");EasyLoading.showError('{state.errMessage ?? ''}');return;}if (state.status.isSubmissionSuccess) {EasyLoading.dismiss();showCupertinoDialog(context: context,builder: (context) {returnAlertDialog(content: Text(LS.of(context, "register_success")),actions: [TextButton(onPressed: (){Navigator.of(context).popUntil(ModalRoute.withName("/"));}, child: Text(LS.of(context, "confirm")))],);});}},child: Align(alignment: Alignment(0, -1),child: Padding(padding: const EdgeInsets.only(top: 31, left: 36, right:36),child: Column(children: [_UsernameInput(),_PasswordInput(),_ConfirmPasswordInput(),const SizedBox(height: 20,),_RegisterButton()]),),));}}
class _RegisterButton extends StatelessWidget {@overrideWidget build(BuildContext context) {return BlocBuilder<RegisterBloc, RegisterState>(builder: (context, state) {return CircleRectButton(child: Text(LS.of(context, "register"), style: TextStyle(letterSpacing: 20)),onPressed: state.status.isValidated? () async {context.read<RegisterBloc>().add(RegisterSubmitEvent());}: null);});}}
BlocListener: 通过BlocListener
来监听状态消息,收到消息 child 不会 rebuild。适合拿来弹出加载页,错误信息等。
BlocBuilder 通过BlocBuilder
来包装需要修改的内容。 这里的在组装页面的时候尽量在涉及到更新的地方使用 BlocBuilder
,也尽可能的考虑buildwhen
属性。保持当必须要更新时才重新 build 的思路。
bloc
bloc 在封装后没什么逻辑,他的思路就是接受页面的事件,转为状态变更返回给页面。
class RegisterBloc extends Bloc<RegisterEvent, RegisterState> {
RegisterBloc(RegisterState initialState) : super(initialState);
@overrideStream<RegisterState> mapEventToState(RegisterEvent event,) async* {try {yield* event.applyAsync(currentState: state, bloc: this);} catch (, stackTrace) {developer.log('$', name: 'RegisterBloc', error: _, stackTrace: stackTrace);yield state;}}}
将对应的事件处理放在 event 里面去执行显然更符合设计模式。代码也会更清晰,而不用做很多判断
if(event is event){do()} else if (event is event) {do()}
event
@immutableabstract class RegisterEvent {const RegisterEvent();Stream<RegisterState> applyAsync({required RegisterState currentState, required RegisterBloc bloc});}
class UsernameChangeEvent extends RegisterEvent {const UsernameChangeEvent(this.username);final String username;
Stream<RegisterState> applyAsync({required RegisterState currentState, required RegisterBloc bloc}) async* {var input = UsernameInput.dirty(username);var status = Formz.validate([input, currentState.password, currentState.confirmPassword]);yield currentState.copyWith(username: input, status: status);}
}
抽象 event,定义事件接口。 子类 event 来接收参数,实现事件接口并抛出新的状态给页面。
state
评论