【问题标题】:Flutter BLoC pattern - How can I navigate to another screen after a stream event?Flutter BLoC 模式 - 如何在流事件后导航到另一个屏幕?
【发布时间】:2019-01-05 03:57:01
【问题描述】:

我的问题是关于BLoC pattern 使用的导航

在我的 LoginScreen 小部件中,我有一个按钮,可将事件添加到 bloc 的 EventSink 中。该集团调用 API 并对用户进行身份验证。 我必须在 LoginScreen Widget 的哪个位置收听流,在它返回成功状态后如何导航到另一个屏幕?

【问题讨论】:

  • 我想你可以在initState 中收听,并根据流的结果使用Navigator.push() 导航
  • *.com/questions/51333474/… 的副本查看我对该问题的回答。
  • @nonybrighto 这个解决方案的问题是我使用了一个 BlocProvider ,它是一个继承的小部件,儿子要访问 bloc 我需要构建函数中的上下文。所以我无法访问initState 中的集团。关于如何解决这个问题的任何想法?
  • 我认为这个答案正是你所追求的:*.com/a/52167972/4743190

标签: dart flutter dart-async reactive-streams


【解决方案1】:

使用 BlockListener

 BlocListener(
  bloc: _yourBloc,
  listener: (BuildContext context, YourState state) {
    if(state is NavigateToSecondScreen){
      Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) {return SecondScreen();}));
    }
  },
  child: childWidget
)

【讨论】:

    【解决方案2】:

    导航器在 blocBuilder 中不起作用,因为在 blocBuilder 中,您只能返回一个小部件

    但是 BlocListener 为我解决了这个问题。

    添加此代码:

    BlocListener(
      bloc: _yourBloc,
      listener: (BuildContext context, YourState state) {
        if(state is NavigateToSecondScreen){
          Navigator.of(context).push(MaterialPageRoute(builder: (BuildContext context) {return SecondScreen();}));
        }
      },
      child: childWidget
    )
    

    【讨论】:

      【解决方案3】:

      首先:如果没有任何业务逻辑,那么就没有必要去YourBloc类。

      但有时需要一些用户的活动来执行 Bloc 类中的一些逻辑,然后 Bloc 类必须决定下一步做什么:只需重建小部件显示对话框,甚至导航到下一条路线。在这种情况下,您必须向 UI 发送一些 State 以完成操作。

      然后又出现了一个问题:Bloc 发送 State 显示 toast 的时候,widget 怎么办?

      这是整个故事的主要问题。

      很多答案和文章推荐使用flutter_block。这个库有BlocBuilderBlocListener。通过这些课程,您可以解决一些问题,但不是 100%。

      在我的例子中,我使用了 BlocConsumer,它管理 BlocBuilderBlocListener 并提供了一种管理状态的绝妙方法。

      来自文档:

      BlocConsumer<BlocA, BlocAState>(
        listenWhen: (previous, current) {
          // Return true/false to determine whether or not
          // to invoke listener with state
        },
        listener: (context, state) {
          // Do stuff here based on BlocA's state
        },
        buildWhen: (previous, current) {
          // Return true/false to determine whether or not
          // to rebuild the widget with state
        },
        builder: (context, state) {
          // Return widget here based on BlocA's state
        }
      )
      

      正如您在 BlocConsumer 中看到的那样,您可以过滤状态:您可以轻松定义状态以重建小部件和状态以显示一些弹出窗口或导航到下一个屏幕。

      【讨论】:

        【解决方案4】:

        类似这样的:

        if (state is PhoneLoginCodeSent) {
            // Dispatch here to reset PhoneLoginFormState
            SchedulerBinding.instance.addPostFrameCallback((_) {
                Navigator.of(context).push(
                    MaterialPageRoute(
                        builder: (context) {
                            return VerifyCodeForm(phoneLoginBloc: _phoneLoginBloc);
                        },
                    ),
                );
                return;
            });
        }
        

        【讨论】: