Flutter_bloc框架使用笔记,后续估计都不太会用了

47 阅读2分钟

_RegisterPageState createState() => _RegisterPageState(); }

class _RegisterPageState extends State { final _registerBloc = RegisterBloc(RegisterState());

@override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(LS.of(context, "register")), ), body: BlocProvider( create: (_) => _registerBloc, child: RegisterScreen(widget.phone), ), ); } }

作为一个主体的页面,定义了route名称。 可以使用StatelessWidget。因为正常也没什么状态管理

在state里面的builder里构建了BlocProvider

body: BlocProvider( create: (_) => _registerBloc, child: RegisterScreen(widget.phone), )

这里是为后续的节点注册了一个RegisterBloc, 从这个节点下级的widget就可以通过Provider.of<RegisterBloc>来获取。 当然也可以有其他的方式比如context.read<RegisterBloc>来获取。

这里也可以把bloc传给screen,可以方便在screen里面获取bloc。而不是通过在配置树里查找bloc。能稍微减少些性能消耗。

  1. screen

screen主要是构建配置页面内容用。

class RegisterScreen extends StatelessWidget { const RegisterScreen( this.phone, { Key? key, }) : super(key: key);

final String phone;

@override Widget 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('message:message:{state.errMessage ?? ''}'); return; } if (state.status.isSubmissionSuccess) { EasyLoading.dismiss(); showCupertinoDialog( context: context, builder: (context) { return AlertDialog( 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 { @override Widget 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().add(RegisterSubmitEvent()); } : null); }); } }

BlocListener: 通过BlocListener来监听状态消息,收到消息child不会rebuild。适合拿来弹出加载页,错误信息等。

BlocBuilder 通过BlocBuilder来包装需要修改的内容。 这里的在组装页面的时候尽量在涉及到更新的地方使用 BlocBuilder,也尽可能的考虑buildwhen 属性。保持当必须要更新时才重新build的思路。

  1. bloc

bloc 在封装后没什么逻辑,他的思路就是接受页面的事件,转为状态变更返回给页面。

class RegisterBloc extends Bloc<RegisterEvent, RegisterState> {

RegisterBloc(RegisterState initialState) : super(initialState);

@override Stream 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() }

  1. event

@immutable abstract class RegisterEvent { const RegisterEvent(); Stream applyAsync({required RegisterState currentState, required RegisterBloc bloc}); }

class UsernameChangeEvent extends RegisterEvent { const UsernameChangeEvent(this.username); final String username;

Stream 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来接收参数,实现事件接口并抛出新的状态给页面。

  1. 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 });

@override List 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, ); }