使用 bloc 更改屏幕

Posted

技术标签:

【中文标题】使用 bloc 更改屏幕【英文标题】:Changing screens using bloc 【发布时间】:2020-03-06 09:01:24 【问题描述】:

我正在尝试使用 bloc 切换屏幕(无状态小部件), 当使用 BlocBuilder 根据状态输出不同的小部件时,上下文将更改为显示的新小部件。 在新小部件中调用状态侦听器。

当状态改变时,我设法显示了一个小部件, 问题是当状态再次发生变化时,上下文发生了变化,并且在显示的小部件中调用了构建器函数。

所以我创建了一个包含该块的继承小部件,因此我可以从子小部件调度一个事件以在父小部件上发生,然后根据状态显示不同的小部件。

class SignupViewManager extends InheritedWidget 
  final SignupBloc bloc;
  final Widget child;

  SignupViewManager(Key key, this.child, this.bloc) : super(key: key, child: child);

  static SignupViewManager of(BuildContext context) 
    return (context.inheritFromWidgetOfExactType(SignupViewManager) as SignupViewManager);
  

  @override
  bool updateShouldNotify(SignupViewManager oldWidget) 
    return true;
  


class SignupHomePage extends StatelessWidget 
  final SignupBloc signupBloc = SignupBloc();

  SignupHomePage(Key key) : super(key: key);

  @override
  Widget build(BuildContext context) 
    return SignupViewManager(
        bloc: SignupBloc(),
        child: BlocProvider<SignupBloc>(
          builder: (context) => signupBloc,
          child: BlocBuilder<SignupBloc, SignupState>(
              builder: (context, state) => _signupBuilder(context, state),
              condition: (previousState, state) => _signupCondition(previousState, state),
        ),
      )
    );
  

  Widget _signupBuilder(BuildContext context, SignupState state) 
    print("IN SIGNUP MAIN BUILDER $state");
    // Changing the UI based on the current state
    if (state is SignupInitial)  // Show credentials for initial state
      return SignupCredentials();
     else if (state is SavedCredentials)  // Show Agreements after credentials has been saved.
      return SignupAgreements(user: state.user);
    

    return Text("default");
  


class SignupCredentials extends StatelessWidget 
  SignupBloc signupBloc;

  void _signup(email, password, confirmPassword) 
    if(password == confirmPassword) 
      signupBloc.add(SaveCredentials(email, password));
     else 
      print("passwords do not match");
    
  

  Widget _bloc() 
    return BlocBuilder<SignupBloc, SignupState>(
        builder: (context, state) 
            print("IN SIGNUP credentials builder $state");

            if(state is SavedCredentials) 
            return SignupDetails();
            

            return Text("$state.runtimeType");
        ,
    );
  


因此,当状态设置为 SignupInitial 时,应出现 SignupCredentials 无状态小部件。 然后当用户输入凭据并提交它们时,会调度 SavedCredentials 事件,并且应该出现 SignupAgreements。 但是会发生什么是 SignupCredentials 构建器正在接收新状态而不是 SignupHomePage。

【问题讨论】:

【参考方案1】:

我解决了这个问题。

我将 bloc 提供程序更改为 SignupBloc 类型。

@override
  Widget build(BuildContext context) 
    return AuthenticationPageLayout(
      color: Colors.white,
      opacity: 0.05,
      child: SignupViewManager(
        child: BlocProvider<SignupBloc>(
            builder: (context) => SignupBloc(),
            child: BlocListener<SignupBloc, SignupState>(
                listener: (context, state) => _signupListener(context, state),
                condition: (previousState, state) => _signupCondition(previousState, state),
                child: BlocBuilder<SignupBloc, SignupState>(
                builder: (context, state) => _signupBuilder(context, state),
                condition: (previousState, state) => _signupCondition(previousState, state),
                )
            )
        );
      )
    );
  

然后我使用此行引用了 bloc 提供者

BlocProvider.of<SignupBloc>(context)

【讨论】:

以上是关于使用 bloc 更改屏幕的主要内容,如果未能解决你的问题,请参考以下文章

使用flutter_bloc提交时如何验证表单?

Flutter 再次触发 bloc 事件

如何使用 BLoC 在颤动的屏幕之间传递数据?

Flutter Bloc 状态管理

Flutter Application Bloc 侦听器未接收到状态更新

使用 bloc 创建全局加载屏幕的最佳方法?