Давайте настроим управление состоянием на нижнем листе Flutter.

Я работал над приложением Flutter to do, когда понял, что хочу переместить свой NewToDo виджет в showModalBottomSheet. Вот гифка текущего пользовательского интерфейса.

В идеале, когда пользователь вводит что-либо в поле title, кнопка «Добавить к выполнению» должна быть включена.

Проблема, с которой я столкнулся, заключалась в том, что значение состояния для title управлялось в виджете MyApp (потому что я также разрешаю функции редактирования, а кнопка редактирования не является частью моего NewToDo), и по какой-то причине NewToDo не улавливал обновленное состояние. Я спросил об этом в StackOverflow и получил довольно лаконичное решение.

Вот код для FloatingActionButton в MyApp:

floatingActionButton: FloatingActionButton(
  onPressed: () {
    showModalBottomSheet<void>(
      context: context,
      builder: (BuildContext context) {
        return NewToDo(titleController, contentController, _addTodo, _clear, _todo);
      });
    }
  },
  child: const Icon(Icons.add),
  backgroundColor: Colors.deepPurple,
),

По сути, происходило то, что NewToDo мог узнать, когда состояние изменилось с момента передачи.

Я знал это, потому что, хотя кнопка не включалась, когда вы что-то набирали в поле ввода текста заголовка, если я что-то набирал, а затем закрывал модальное окно и снова открывал его, кнопка была бы активна.

Проблема заключалась в том, что NewToDo не знал, что нужно повторно выполнить рендеринг, потому что он заключен в showModalBottomSheet и builder.

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

Поскольку NewToDo заключен в другой построитель и имеет другой контекст, чем родительский виджет, NewToDo не перестраивается при обновлении состояния.

Итак, как я это обошел? Следует упомянуть, что в моем виджете NewToDo я использую TextField для захвата данных заголовка.

А в моем виджете TextField используйте TextEditingController, чтобы отслеживать значения, помещаемые в заголовок TextField. Этот контроллер доступен для прослушивания, что означает, что его можно использовать, чтобы сообщить клиенту, что объект обновлен (т. Е. Состояние).

Подробнее о TextField и TextEditingController и управлении состоянием читайте в моем предыдущем сообщении в блоге.

Так что все, что мне нужно сделать, это обернуть NewToDo, это то, что называется ValueListenableBuilder. Это означает, что этот builder может перестроить своего дочернего элемента (в данном случае NewToDo), если значение, которое он прослушивает, изменяется.

Вот как выглядит наш обновленный FloatingActionButton:

floatingActionButton: FloatingActionButton(
  onPressed: () {
    showModalBottomSheet<void>(
      context: context,
      builder: (BuildContext context) {
        return ValueListenableBuilder(
          valueListenable: titleController,
          builder: (context, _content, child) {
            return NewToDo(titleController, contentController, _addTodo, _clear, _todo);
          });
      });
  },
  child: const Icon(Icons.add),
  backgroundColor: Colors.deepPurple,
),

Эта обновленная часть нашего FloatingActionButton оборачивает наш NewToDo виджет в ValueListenableBuilder, который имеет titleController в качестве значения для свойства valueListenable.

Это означает, что наш конструктор будет специально прислушиваться к обновлениям нашего titleController, который является экземпляром TextEditingController, присвоенным заголовку TextField.

У меня также есть еще одно свойство builder, которое позволяет нам создавать дочерний виджет внутри ValueListenableBuilder, заключенного в слушатель. В нашем случае дочерний виджет NewToDo.

Давайте посмотрим, как работает наше приложение, когда я использовал ValueListenableBuilder:

Теперь у нас есть построитель, который ожидает обновления определенного значения и NewToDo обновляет вместе со значением состояния MyApp title. Идеально!

Вы видели, как я решил одну из задач для приложения со списком дел. Следите за обновлениями, и я расскажу о некоторых других проблемах, с которыми я столкнулся, и о том, как я их решил!

Весь код этого руководства находится на GitHub.

Обновите бесплатную подписку на Medium до платной, и всего за 5 долларов в месяц вы получите неограниченное количество рассказов от тысяч писателей без рекламы. Это партнерская ссылка, и часть вашего членства помогает мне получать вознаграждение за контент, который я создаю. Спасибо!

Справочные материалы по API

  1. API showModelBottomSheet
  2. Класс TextField
  3. Класс TextEditingController
  4. Класс ValueListenableBuilder
  5. Класс FloatingActionButton
  6. Свойство valueListenable