首页 > 解决方案 > Flutter:与 Provider 的 UI 反应

问题描述

  1. 在某些情况下,我想使用 Navigator 导航到另一个屏幕。 我可以使用 BlocListener 轻松实现它:
  BlocListener<BlocA, BlocAState>(
  bloc: blocA,
  listener: (context, state) {
      if (state is Success) {              
          Navigator.of(context).pushNamed('/details');
      }  
  },
  child: Container(),
)

但是我在纯提供者中找不到它的直接等价物。我看到的唯一方法是交换屏幕:

home: Consumer<Auth>(
    builder: (_, auth, __) => auth.user == null ? LoginPage() : MainPage()
)

这是一种常见的方式。但它不会使用 Navigator,因此它只会“弹出”MainPage 而没有屏幕转换。

  1. 在某些情况下,我想在 UI 中播放一些动画。

我在文档中发现Listenable该类旨在处理动画,但没有详细解释。

  1. 在某些情况下,我想清除 TextEditingController。

  2. 在某些情况下,我想显示一个对话框。

还有更多类似的任务……如何解决?提前致谢!

标签: flutterdartprovider

解决方案


经过一番研究,我找到了一种方法。我不确定这是否是唯一或最好的方式,或者 Provider 的创建者所预见的方式,但它确实有效。

这个想法是在我的 Store 类(我的意思是 Provider 提供的业务逻辑类)中保留一个助手 Stream,并在我的小部件中订阅它的更改。

所以在我的商店课程中,我有:

  final _eventStream = StreamController.broadcast();
  Stream get eventStream => _eventStream.stream;
  
  void dispose() {
    _eventStream.close();
    super.dispose();
  }

我在动作中向这个流添加事件:

  void navigateToNextScreen() {    
    _eventStream.sink.add('nav');
  }

  void openDialog() {    
    _eventStream.sink.add('dialog');
  }

在我的 UI 小部件中,我有:

  @override
  void afterFirstLayout(BuildContext context) {
    context.read<Transactions>().eventStream.listen((event) {
      if (event == 'nav') {
        Navigator.push(
          context,
          MaterialPageRoute(
            builder: (ctx) => SecondScreen(),
          ),
        );
      } else if (event == 'dialog') {
        showDialog(
            context: context,
            builder: (context) => AlertDialog(content: Text("Meow")));
      }
    });    
  }

我在这里使用afterFirstLayout了包中的生命周期方法after_layout,它只是一个包装器WidgetsBinding.instance.addPostFrameCallback


07.07.20 UPD.:刚刚找到一个可以用于事件反应的包: https ://pub.dev/packages/event_bus

它基本上使用与引擎盖下的 StreamController 相同的方法。


推荐阅读