У меня есть виджет с отслеживанием состояния Menu
, который является родительским виджетом для нескольких экземпляров дочернего виджета MenuIcon
, который возвращает контейнер. Пользователь может касаться виджетов MenuIcon
индивидуально, чтобы они выделялись, когда active
bool истинно, и не выделялись, когда это не так. Прямо сейчас все это контролируется в классе MenuIcon
, что, судя по чтению здесь , не лучший подход, учитывая, что состояние каждой из иконок будет играть важную роль в приложении, и поэтому Я хочу иметь возможность управлять им в родительских виджетах. Но я не совсем уверен, как это сделать, в приведенном ранее руководстве просто один родительский виджет -> один дочерний виджет, поэтому очень легко управлять состоянием из родительского виджета. Но в этом случае, поскольку родительский виджет содержит несколько экземпляров дочерних виджетов, каждый из которых имеет собственное активное / неактивное состояние, я не могу придумать простой способ сделать это.
В настоящее время моя иерархия выглядит так: Я предполагаю, что MenuIcons будет просто управлять своей собственной анимацией, класс Menu
- для управления состояниями каждого MenuIcon
, а HomePage
- для хранения списка всех MenuIcon
, активных в данный момент.
Код для классов Menu
и MenuIcon
следующий:
//----------------- Menu ------------------------------------------
//These classes control the scrollable menu that appears when the
//dropdown is pressed
class Menu extends StatefulWidget {
final String _category;
Menu(this._category);
@override
_MenuState createState() => _MenuState(category: this._category);
}
class _MenuState extends State<Menu> {
List<Offer> _offersList = createOffers();
String category;
_MenuState({@required this.category});
//build method
Widget build(BuildContext context) {
final _menuItems = List<Container>();
//builds an item widget if the category is correct.
for (int i = 0; i < _offersList.length; i++) {
if (this.category == _offersList[i].category) {
// adds a container containing the MenuIcon object, with the offer
// in question passed through _offersList[i]
_menuItems.add(Container(
child: MenuIcon(
offer: _offersList[i],
)));
}
}
//This particular widget tree allows to have a horizontal scrolling
//menu within a fixed widget
if (_menuItems.length > 0) {
return SizedBox(
child: Row(
children: [
Expanded(
child: ListView(
children: _menuItems,
scrollDirection: Axis.horizontal,
)),
],
),
height: 154,
);
} else {
return Row(
children: [
Container(
child: Text(
'Sorry! There are no offers available for this category',
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 14.0,
),
),
padding: EdgeInsets.only(left: 12),
),
],
);
}
}
}
//------------------- MenuIcon class -----------------------------
class MenuIcon extends StatefulWidget {
Offer offer;
MenuIcon({@required this.offer});
@override
_MenuIconState createState() => _MenuIconState(this.offer);
}
class _MenuIconState extends State<MenuIcon> {
Offer _offer;
bool active;
_MenuIconState(this._offer) {
this.active = false;
}
void _handleTap() {
setState(() {
active = !active;
});
}
Widget build(BuildContext context) {
//print('icon rebuilt with active = $active');
var label = _offer.discount.toString();
return Container(
child: GestureDetector(
child: Column(
children: [
_offer.image,
Text(
'$label% off',
style: TextStyle(
color: Colors.red,
fontSize: 14.0,
),
),
],
mainAxisAlignment: MainAxisAlignment.center,
),
onTap: _handleTap,
),
//changes the colour if the icon is selected or not
color: active ? Colors.yellow : Colors.white,
);
}
}