Неожиданное поведение состояния ListEntry после отключения

#flutter

#флаттер

Вопрос:

На странице у меня есть ListView с элементами ListEntry. ListEntry является состоянием, полным и имеет свойство _visible, которое по умолчанию равно false. Существует метод _onLeadingPressed, который позволяет инвертировать свойство _visible — с ним нет проблем. Каждый ListEntry является недопустимым, поэтому я могу отклонить его.

 class ListEntry extends StatefulWidget {
  @override
  _ListEntryState createState() => _ListEntryState();
}

class _ListEntryState extends State<ListEntry> {
  bool _visible = false;

  // there is an option to change `_visible` for every `ListEntry`
  void _onLeadingPressed() {
    setState(() {
      _visible = !_visible;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Dismissible(
      key: UniqueKey(),
      direction: DismissDirection.horizontal,
      onDismissed: (direction) async {
        _visible = false;
        // some action here
      },
      child: ListTile(
        //every ListTile has a logic to show some info based on `_visible` value
        ...
      ),
    );
  }
}
  

А теперь интересная часть.
Например, текущий ListView содержит эти элементы:

  • ListEntry 1 (_visible = false)
  • ListEntry 2 (_visible = true)
  • ListEntry 3 (_visible = false)

Давайте отклоним ListEntry 1. Теперь ListView выглядит следующим образом:

  • ListEntry 2 (_visible = false)
  • ListEntry 3 (_visible = true)

Почему тогда у ListEntry 3 значение true, а у ListEntry 2 также значение false? Разве это не должно быть так после увольнения первого элемента?

  • ListEntry 2 (_visible = true)
  • ListEntry 3 (_visible = false)

Ответ №1:

Я думаю, что проблема, с которой вы столкнулись, связана с ключами. При вызове setState будет сгенерирован новый уникальный ключ, который будет назначен ListEntry, и flutter не сможет найти ни одного виджета с этим ключом в своем дереве элементов, поэтому вы можете получить такое поведение.

Попробуйте использовать что-то специфичное для этого ListEntry в качестве ключа, например, имя, заголовок или что-либо специфичное для ListEntry, чтобы при вызове setState вы не генерировали новый уникальный ключ, но использовали предыдущий, и Flutter может найти соответствующее состояние виджета с тем же ключом. Это должно сохранить состояние, как и раньше, и показывать правильные значения.

Проверьте эту часть скучного шоу Flutter, в котором есть такая же проблема, а также это руководство.