Flutter: реакции пользовательского интерфейса с провайдером - PullRequest
2 голосов
/ 20 июня 2020
  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()
)

Это обычный способ. Но он не будет использовать навигатор, поэтому он будет просто «выдавать» MainPage без перехода экрана.

В некоторых случаях я хочу воспроизвести анимацию в пользовательском интерфейсе.

В документации я обнаружил, что класс Listenable предназначен для работы с анимациями, но он не объясняется подробно.

В некоторых случаях я хочу очистить TextEditingController.

В некоторых случаях я хочу показать диалоговое окно.

И еще подобные задачи ... Как это решить? Заранее спасибо!

1 Ответ

0 голосов
/ 21 июня 2020

После некоторых исследований я нашел способ. Я не уверен, единственный или лучший способ, или способ, предусмотренный создателем провайдера, однако он работает.

Идея состоит в том, чтобы сохранить вспомогательный поток внутри моего класса Store (я имею в виду бизнес- logi c, предоставленный поставщиком), и подписаться на его изменения в моем виджете.

Итак, в моем классе Store у меня есть:

  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');
  }

В моем виджете пользовательского интерфейса:

  @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 под капотом.

...