Какие есть способы получения 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 шт):
Не совсем уверен чего вы хотите добиться. Старайтесь управлять состоянием дочерних виджетов в родительском виджете, особенно в 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,
),
);
}
}