флаттер снэк-бар на основе потока - PullRequest
0 голосов
/ 03 января 2019

В настоящее время у меня есть интересная проблема, связанная с отображением снэк-бара на основе действий пользователя.

Выше звуки очень тривиальны, но давайте уточним:

У меня есть 2 экрана:

  1. список сотрудников
  2. Добавить сотрудника

Приложение использует шаблон блока (с потоками / rxdart).

Вот что я хочу:

  • Пользователь нажимает кнопку FAB «Добавить сотрудника» на экране списка сотрудников и переходит к экрану «Добавить сотрудника» (работает отлично)
  • Пользователь вводит данные сотрудника и нажимает кнопку «Сохранить»
  • После сохранения сотрудник добавляется в поток и обновляется экран списка сотрудников (работает нормально)
  • Пользователь перемещается НАЗАД к списку сотрудников (работает нормально)
  • Snackbar показывает, что сотрудник был успешно добавлен (это проблема)

Я пробовал несколько способов реализовать это:

Добавить новый поток (employeeAdded), и когдадобавление empLoyee к потоку сотрудников, дополнительно добавьте логическое значение для сотрудника добавил.

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

Это создает всевозможные проблемы, например, пытается отобразить панель закусок до того, как страницабыла (пере) сборка и т. д.

Вопрос двоякий: какова хорошая практика UX для этого сценария и что было бы хорошим решением для этой проблемы?

(опубликуеткод по запросу)

Спасибо за помощь!

Ответы [ 3 ]

0 голосов
/ 09 января 2019

@ joey Я нашел решение, но не уверен, что оно лучшее.Сейчас я меняю свое приложение на шаблон блока, возникла та же проблема, что и у вас, поэтому я сделал это:

В своем файле блока я поместил контроллер для scaffoldState:

ScaffoldState scaffold;

StreamController<ScaffoldState> _scaffoldController = StreamController<ScaffoldState>();
StreamSink<ScaffoldState> get setScaffold => _scaffoldController.sink;

Вконструктор файла блока, который я слушаю в этом потоке:

LoginBloc(){
    _scaffoldController.stream.listen((sc){ scaffold = sc;});
}

В виджете я опускаю scaffoldState всякий раз, когда я хочу его использовать:

onPressed:() {
   bloc.setScaffold.add(Scaffold.of(context));
}

, поэтому я могу показатьзакусочные как обычно из блока:

scaffold.showSnackBar(SnackBar(content: Text(hi world'),),);
0 голосов
/ 04 марта 2019

Оберните ваш body (дочерний элемент вашего Scaffold, в вашем случае возвращенный _buildBody) с Builder, чтобы вы могли написать некоторый "бесплатный" код с context.

Теперь вы можете прослушивать поток с помощью предоставленного вами обработчика (как вы уже сделали), но на этот раз вы регистрируете слушателя только один раз для Scaffold сборки (и не регистрируете слушателя при каждом событии, происходящем в employeesAddedпоток).

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Builder(
        builder: (BuildContext context) {
          bloc.employeesAdded.listen(
            (_) {
              Scaffold.of(context).showSnackBar(
                SnackBar(
                  content: Text('Employee added'),
                ), // SnackBar
              );
            },
          );

          return _buildBody(bloc);
        },
      ), // Builder
    ); // Scaffold
  }
0 голосов
/ 03 января 2019

Хотя это не мой любимый ответ, я также не уверен, есть ли лучшая альтернатива; это то, что я сделал как временное исправление для будущих наблюдателей:

Создайте новый поток (в моем случае employeeAdded), после добавления сотрудников, также создайте запись в потоке:

  final _employees = BehaviorSubject<List<Employee>>(seedValue: List<Employee>());
  final _employeeAdded = BehaviorSubject();

  // streams (out)
  Observable<List<Employee>> get employees => _employees.stream;
  Observable<dynamic> get employeesAdded => _employeeAdded.stream;

  addEmployee(Employee employee) async {
    final newList = <Employee>[]..addAll(_employees.value)..add(employee);
    await _employeeRepo.upsertEmployee(employee);
    _employees.add(newList);

    _employeeAdded.add(true);
    //FIXME: Save to db
  }

Обратите внимание, что в employeeAdded нет seedValue, это необходимо для того, чтобы при начальной загрузке не отображалась снэк-бар.

На моем экране / странице у меня есть эшафот; это тело вызывает другой метод, который должен объяснить остальную часть кода:

 Widget _buildBody(EmployeeBloc bloc) {
    return StreamBuilder(
      stream: bloc.employees,
      builder: (context, snapshot) {
        if (!snapshot.hasData) {
          bloc.employeesAdded.listen(
            (_) => Scaffold.of(context).showSnackBar(
                  SnackBar(
                    content: Text('Employee added'),
                  ),
                ),
          );
          bloc.seedEmployees();
          return Center(
            child: Text("No employees"),
          );
        }
        return _buildList(bloc, snapshot.data);
      },
    );
  }

Обратите внимание на прослушивание блока с hasData if.

Пока это работает, но хотелось бы знать, есть ли более аккуратный пример.

...