Flutter_bloc 框架使用笔记,后续估计都不太会用了 (1)
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: [_UsernameIn
put(),_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
class RegisterState extends Equatable {final UsernameInput username;final PasswordTwoInput password;final PasswordTwoInput confirmPassword;final FormzStatus status;final String? errMessage;RegisterState({this.username = const UsernameInput.pure(),this.password = const PasswordTwoInput.pure(),this.confirmPassword = const PasswordTwoInput.pure(),this.status = FormzStatus.pure,this.errMessage});
@overrideList<Object> get props => [username, password, confirmPassword, status];
RegisterState copyWith({UsernameInput? username,PasswordTwoInput? password,PasswordTwoInput? confirmPassword,FormzStatus? status,}) {return RegisterState(username: username ?? this.username,password: password ?? this.password,confirmPassword: confirmPassword ?? this.confirmPassword,status: status ?? this.status,);}}
state 可以考虑抽象 state 和单独一个 state 类。看具体业务吧。如果属性很简单,可以考虑抽象。属性比较多的情况下就没必要抽象了。
思路总结
Page 作为整个页面的对外对象,给外部调用,同时定义和注册了本页面需要用的 bloc.
Screen 配置了整个页面展示的 widget。并把事件抛给 bloc.通过接收 bloc 的最新状态,并 rebuild UI.
bloc 里面处理事件并转为 state 返回给页面题外话
Cubit
还有一套 cubit 的简单模板,其实就是把 bloc 换成了 cubit。去掉了 event 的逻辑。screen 里面事件调用 cubit 的方法。在 cubit 里面 emit(new state).如此页面就可以接收到最新的状态了。
GET
在使用体验上 GET 框架不依赖 context。对于使用体验来说应该更好些。对于简单的状态管理,也是 GET 更方便。
评论