У меня есть родительский виджет, который содержит список элементов и индекс выбранного элемента. Дочерний виджет сообщает родителю, когда элемент выбран. Если я передам функцию isSelected (index) дочернему виджету, дочерний виджет обновится, чтобы показать, какой элемент выбран. Если я передаю selectedIndex int дочернему виджету, selectedIndex обновляется в родительском, но не дочернем виджете.
Рабочая версия с использованием функции isSelected (index)
import 'package:flutter/material.dart';
class IsSelected extends StatefulWidget {
@override
State<StatefulWidget> createState() => IsSelectedState();
}
class IsSelectedState extends State<IsSelected> {
List<int> _items = List.from([0]);
int _selectedIndex = -1;
@override
Widget build(BuildContext context) {
return SafeArea(
child: Column(
children: <Widget>[
Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.indeterminate_check_box),
onPressed: () {
setState(() {
_items.removeAt(_selectedIndex);
});
}
),
IconButton(
icon: Icon(Icons.add_box),
onPressed: () {
setState(() {
_items.add(_items.length);
});
}
)
]
),
Expanded(
child: ItemList(
items: _items,
isSelected: (index) => _selectedIndex == index,
onSelect: (index) => setState(() {
_selectedIndex = index;
})
)
)
],
)
);
}
}
class ItemList extends StatefulWidget {
final List<int> _items;
final Function _isSelected;
final Function _onSelect;
ItemList({items, isSelected, onSelect}) :
_items = items,
_isSelected = isSelected,
_onSelect = onSelect;
@override
State<StatefulWidget> createState() => ItemListState(
items: _items,
isSelected: _isSelected,
onSelect: _onSelect
);
}
class ItemListState extends State<ItemList> {
final List<int> _items;
final Function _isSelected;
final Function _onSelect;
ItemListState({items, isSelected, onSelect}) :
_items = items,
_isSelected = isSelected,
_onSelect = onSelect;
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _items.length,
itemBuilder: (BuildContext context, int index) {
// I used a withOpacity(0) below to make the border transparent
// The background colors of the ListView isn't quite white
final Color borderColor = _isSelected(index) ?
Theme.of(context).primaryColor : Colors.white.withOpacity(0);
return GestureDetector(
onTap: () => _onSelect(index),
child: Container(
padding: EdgeInsets.symmetric(vertical: 20, horizontal: 20),
decoration: BoxDecoration(
border: Border.all(
color: borderColor,
width: 2
)
),
child: Row(
children: <Widget> [
Expanded(
child: Text(_items[index].toString(),
textAlign: TextAlign.left,
overflow: TextOverflow.ellipsis,
)
)
]
)
)
);
},
);
}
}
Не работает версия, передавая selectedIndex дочернему виджету
import 'package:flutter/material.dart';
class SelectedIndex extends StatefulWidget {
@override
State<StatefulWidget> createState() => SelectedIndexState();
}
class SelectedIndexState extends State<SelectedIndex> {
List<int> _items = List.from([0]);
int _selectedIndex = -1;
@override
Widget build(BuildContext context) {
return SafeArea(
child: Column(
children: <Widget>[
Row(
children: <Widget>[
IconButton(
icon: Icon(Icons.indeterminate_check_box),
onPressed: () {
setState(() {
_items.removeAt(_selectedIndex);
});
}
),
IconButton(
icon: Icon(Icons.add_box),
onPressed: () {
setState(() {
_items.add(_items.length);
});
}
)
]
),
Expanded(
child: ItemList(
items: _items,
selectedIndex: _selectedIndex,
onSelect: (index) => setState(() {
_selectedIndex = index;
})
)
)
],
)
);
}
}
class ItemList extends StatefulWidget {
final List<int> _items;
final int _selectedIndex;
final Function _onSelect;
ItemList({items, selectedIndex, onSelect}) :
_items = items,
_selectedIndex = selectedIndex,
_onSelect = onSelect;
@override
State<StatefulWidget> createState() => ItemListState(
items: _items,
selectedIndex: _selectedIndex,
onSelect: _onSelect
);
}
class ItemListState extends State<ItemList> {
final List<int> _items;
final int _selectedIndex;
final Function _onSelect;
ItemListState({items, selectedIndex, onSelect}) :
_items = items,
_selectedIndex = selectedIndex,
_onSelect = onSelect;
@override
Widget build(BuildContext context) {
return ListView.builder(
itemCount: _items.length,
itemBuilder: (BuildContext context, int index) {
// I used a withOpacity(0) below to make the border transparent
// The background colors of the ListView isn't quite white
final Color borderColor = _selectedIndex == index ?
Theme.of(context).primaryColor : Colors.white.withOpacity(0);
return GestureDetector(
onTap: () => _onSelect(index),
child: Container(
padding: EdgeInsets.symmetric(vertical: 20, horizontal: 20),
decoration: BoxDecoration(
border: Border.all(
color: borderColor,
width: 2
)
),
child: Row(
children: <Widget> [
Expanded(
child: Text(_items[index].toString(),
textAlign: TextAlign.left,
overflow: TextOverflow.ellipsis,
)
)
]
)
)
);
},
);
}
}
Я понимаю, что в первой версии функция, которую я передаю дочернему виджету, никогда не изменяется. Вот почему у меня нет проблем с отображением выбранного элемента. Может ли кто-нибудь помочь мне понять, чего мне не хватает во втором примере. Почему флаттер не обновляет selectedIndex в дочернем виджете? Используя отладчик, я вижу, что дочерний виджет перестраивается при обновлении selectedIndex, но значение в дочернем виджете остается прежним. Я родом из React, где все, что мне нужно сделать, чтобы обновить ребенка, это обновить реквизит. Разве это не так, как работает Flutter?