Flutter:如何在控制器中触发 bloc 事件?

Flutter: How to trigger a bloc event in the controller?

总而言之,我希望“context.read().add(EnabledEvent())”从控制器本身或我可以用来从控制器触发事件​​并更新状态的其他替代方案工作:

class SplashCtrl extends GetxController {

  @override
  void onReady() {
    User user = loadUser();
    if (user.isExampleEnabled) {
      context.read<ExampleBloc>().add(EnabledEvent());
    }
  }

我尝试的另一件事是:

ExampleBloc testBloc = ExampleBloc();
testBloc.add(TestEvent());

在控制器中,它似乎确实触发了事件,但 UI 不会随着状态变化而更新。我似乎真的需要 Context 来改变它。有什么想法吗?

更多细节和背景:

我不仅要在页面本身触发 bloc 事件,还要在页面的控制器中触发!

所以我的 flutter 应用程序中有一些页面,每个视图都有一个这样设置的控制器:

class SplashPage extends GetView<SplashCtrl> {
  @override
  Widget build(BuildContext context) {
    Get.lazyPut(() => SplashCtrl());
    return Scaffold(...);
  }
}

SplashCtrl 是此页面的控制器。这个启动视图页面是第一个加载它的页面之一,当它被添加并准备好时(基本上是立即)运行功能,例如检查用户是否登录并将他们的数据加载到应用程序,如下所示:

class SplashCtrl extends GetxController {

  @override
  void onReady() {
    // run stuff here
  }

我已经能够在页面中创建 lambda 函数并根据它们的作用触发事件并像这样切换:


IconSwitchedButtonUi(
  value: state.isExampleOn,
  icon: Images.toggleIcon,
  title: "Is Example enabled?",
  onChanged: (value) {
  if (value) {
    context.read<ExampleBloc>().add(EnabledEvent());
    } else {
    context.read<ExampleBloc>().add(DisabledEvent());
    }
  },
),

但现在我需要一个 bloc 事件来触发并稍微更改状态,如果用户对他们的字段之一具有特定值。我怎么做?如何从控制器中触发事件? “context.read”不起作用,因为控制器没有上下文,或者有?

ExampleBloc testBloc = ExampleBloc(); testBloc.add(TestEvent());

这是行不通的,因为你正在声明一个全新的 bloc 实例,它没有通过任何 BlocProvider 连接到你的小部件树,因此你无法触发 this 会发出状态的集团事件 BlocBuilder 可以做出反应。由于没有提供给小部件树的 bloc read() 找不到这个 bloc。

为了完成这项工作,您需要:

Pass BuildContextBlocProvider
提供的一些 Bloc 或 Cubit
void foo(BuildContext context) {
  User user = loadUser();
  if (user.isExampleEnabled) {
    context.read<ExampleBloc>().add(EnabledEvent());
  }
}
..或者直接在控制器内部监听 bloc 变化
class SplashCtrl extends GetxController {
  SplashCtrl(MyBloc bloc) {
    bloc.stream.listen((event) {
    // React to bloc changes here
    if (event is MyBlocEvent) {
      // Do something
      }
    }
  }
}

请记住,即使在这种方法中,给予 SplashCrtl 构造函数 的 bloc 实例也必须与 BlocProvider 按顺序提供给小部件树的 相同为了这个工作。

我能够通过向我的控制器添加一个延迟的 BuildContext 来解决这个问题:

class SplashCtrl extends GetxController {

  late BuildContext context;

  @override
  void onReady() {
    // run stuff here
  }

之后,在页面本身中,我像这样传递上下文:

class SplashPage extends GetView<SplashCtrl> {
  @override
  Widget build(BuildContext context) {
    controller.context = context;
    Get.lazyPut(() => SplashCtrl());
    return Scaffold(...);
  }
}

然后我就可以在控制器内部使用上下文了!!

if (value) {
    context.read<ExampleBloc>().add(EnabledEvent());
    } else {
    context.read<ExampleBloc>().add(DisabledEvent());
    }
  },