[英]Flutter: Controlling the states of multiple child widgets from a single parent widget
我有一个Menu
状态小部件,它是返回容器的MenuIcon
子小部件的多个实例的父小部件。 用户可以单独点击MenuIcon
小部件,以便在active
布尔为真时突出显示,而不是在不为真时突出显示。 现在这一切都在MenuIcon
class中进行控制,考虑到每个图标的 state 将在应用程序中发挥重要作用,因此我希望能够管理它。在父小部件中。 但我不确定如何执行此操作,之前链接的教程只有一个父小部件 -> 一个子小部件,因此从父小部件管理 state 非常容易。 但在这种情况下,由于父小部件拥有多个子小部件实例,每个实例都有自己的活动/非活动 state 我想不出一个简单的方法来做到这一点。
目前我的层次结构如下所示: 我打算让 MenuIcon 简单地管理自己的 animation,让Menu
class 管理每个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,
);
}
}
另一个可行的选项是 pub.dev 上提供的 Async_Redux package
它的样板代码更少,并且可以非常轻松地实现 state。 您可以配置 ReduxActions 以从您的操作中操作 state。 整个应用程序对 state 操作做出反应。 然后使用 ReduxSelector 显示每个屏幕上的特定更改。
探索:
https://pub.dev/packages/async_redux
https://pub.dev/packages/provider_for_redux
有大量文档可用。
https://www.fireship.io也有一些关于 state 管理的有趣内容。
您可以使用bloc package 来处理子树的 state(在这种情况下,菜单作为根)
这里有一个例子:
class MenuBloc extends Bloc<int, int> {
MenuBloc() : super(0);
@override
Stream<int> mapEventToState(int event) async* {
yield event;
}
class Menu extends StatelessWidget {
@override
Widget build(BuildContext context) {
return BlocProvider<MenuBloc>(
create: (context) => MenuBloc(),
child: Column(
children: [
MenuIcon(menuIndex 0),
MenuIcon(menuIndex: 1),
MenuIcon(menuIndex: 2),
],
),
);
}
}
class MenuIcon extends StatelessWidget {
final int menuIndex;
const MenuIcon({Key key, this.menuIndex}) : super(key: key);
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => _updateState(context),
child:
BlocBuilder<MenuBloc, int>(builder: (context, state) {
final isActive = menuIndex == state;
return Container();
}),
);
}
void _updateState(BuildContext context) {
BlocProvider.of<MenuBloc>(context).add(menuIndex);
}
}
如果您需要在单击 MenuIcon 时在子树中的任何位置执行某些操作,则可以使用 BlocListener 每次 state 更改时触发
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.