Какие есть способы получения currentState или вызова setState виджетов в ListView? (желательно по их индексу)

Описание ситуации:

Возьмем общую (распространенную, частую) ситуацию в которой через ListView.builder динамически строится список stateful виджетов.
Для простоты представим что у каждого виджета в списке может быть одно из двух состояний по булевому свойству, текущее состояние меняется с анимацией (внутренняя реализация в виджетах через их локальный State), и что позиции виджетов в списке постоянны.
Предполагается анимированное изменение состояний сразу нескольких виджетов в списке по некоторому "внешнему" событию (неважно по какому, допустим по нажатию кнопки в AppBar).

Проблема:

Если для переключения состояния виджетов в списке мы используем параметр их конструктора, то тем самым будем перестраивать их - и анимация перехода между состояниями не будет выполняться (т.к. виджеты при этом просто заменяются новыми).
Найдя/добавив в классе стейта таких виджетов метод для программного изменения состояния, условно toggle(newStateValue), сталкиваемся с проблемой - непонятно как этот метод вызвать для виджета в определенной позиции в списке, при том что виджеты в ListView создаются builder-функцией, а у листвью нет свойства/метода вида "childByIndex".

Суть вопроса:

Как можно менять локальный State / вызывать методы стейта некоторых stateful виджетов в ListView зная их индексы? То есть, менять состояние виджетов без их перестраивания с потерей анимированного перехода
// Проблема тут не в написании кода. Суть проблемы именно в том, что когда список строится динамически (вместо декларативного описания каждого его элемента) - неясно как вообще можно получить объект State виджета в ListView, зная позицию виджета в списке. Другими словами, неясен путь решения подобных задач (общая логика решения).

Рассуждения на данный момент:
Можно процедурно строить List виджетов и затем передавать его в ListView, но тогда теряется целый ряд плюшек реактивного перестраивания дерева виджетов и декларативность (такое решение противоречит flutter-way).
Еще есть идея использовать GlobalKey в виджетах внутри списка (запоминая ключи в List'e), но думаю что так получится утечка памяти - то есть, объекты State не смогут нормально разрушаться из-за ссылок на них. Плюс, глобальные ключи это как глобальные переменные (в случае локального списка, это явно оверкилл).


Ответы (1 шт):

Автор решения: Dinario

Не совсем уверен чего вы хотите добиться. Старайтесь управлять состоянием дочерних виджетов в родительском виджете, особенно в listview. Состояния всех элементов будут под контролем.

class MyHomePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {

  List<bool> items = [
    false,
    false,
    false,
    false,
  ];

  @override
  Widget build(BuildContext context) {

    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          setState(() {
            items[1] = true;
            items[3] = true;
          });
        },
      ),
      body: ListView.builder(
        itemBuilder: (context, index){
          return Item(
            selected: items[index],
            onTap: () {
              setState(() {
                items[index] = !items[index];
              });
            },
          );
        },
        itemCount: items.length,
      )
    );
  }
}



class Item extends StatelessWidget{

  final VoidCallback onTap;

  final bool selected;

  const Item({Key key, this.onTap, this.selected}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return InkWell(
      onTap: () => onTap(),
      child: AnimatedContainer(
        width: double.infinity,
        height: 40,
        duration: Duration(seconds: 1),
        color: selected ? Colors.green : Colors.red,
      ),
    );
  }

}
→ Ссылка