[英]Flutter: Controlling the states of multiple child widgets from a single parent widget
I have a Menu
Stateful Widget which is a Parent Widget to multiple instances of a MenuIcon
child widget which returns a container.我有一个
Menu
状态小部件,它是返回容器的MenuIcon
子小部件的多个实例的父小部件。 The user is able to tap the MenuIcon
widgets individually so they highlight when an active
bool is true and don't when it is not.用户可以单独点击
MenuIcon
小部件,以便在active
布尔为真时突出显示,而不是在不为真时突出显示。 Right now this is all controlled within the MenuIcon
class, which from reading here is not the best approach considering that the state of each of the Icons are going to play an important role in the app, and so I want to be able to manage it within the parent widgets.现在这一切都在
MenuIcon
class中进行控制,考虑到每个图标的 state 将在应用程序中发挥重要作用,因此我希望能够管理它。在父小部件中。 But I'm not exactly sure how to do this, the tutorial linked earlier has simply one parent widget -> one child widget and so it is very easy to manage the state from the parent widget.但我不确定如何执行此操作,之前链接的教程只有一个父小部件 -> 一个子小部件,因此从父小部件管理 state 非常容易。 But in this case since the parent widget holds multiple instances of the child widgets each with their own active/inactive state I can't think of an easy way to do this.
但在这种情况下,由于父小部件拥有多个子小部件实例,每个实例都有自己的活动/非活动 state 我想不出一个简单的方法来做到这一点。
Currently my hierarchy looks like this:目前我的层次结构如下所示:
I intend for the MenuIcons to simply manage their own animation, the
Menu
class to manage the states of each MenuIcon
, and the HomePage
to hold a list of every MenuIcon
that is currently active.我打算让 MenuIcon 简单地管理自己的 animation,让
Menu
class 管理每个MenuIcon
的状态,并让HomePage
保存当前处于活动状态的每个MenuIcon
的列表。
The code for the Menu
and MenuIcon
classes are as follows: 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,
);
}
}
You can check the package provider , using this it is easy to manage UI in every page,您可以查看 package提供程序,使用它可以轻松管理每个页面中的 UI,
Adding some articles添加一些文章
Another viable option is the Async_Redux package available on pub.dev另一个可行的选项是 pub.dev 上提供的 Async_Redux package
It has way less boilerplate code and allows very easy state implementation.它的样板代码更少,并且可以非常轻松地实现 state。 You can configure ReduxActions to manipulate state from your actions.
您可以配置 ReduxActions 以从您的操作中操作 state。 The whole app reacts to the state manipulations.
整个应用程序对 state 操作做出反应。 ReduxSelectors are then used to show the specific changes on every screen.
然后使用 ReduxSelector 显示每个屏幕上的特定更改。
Do explore:探索:
https://pub.dev/packages/async_redux https://pub.dev/packages/async_redux
https://pub.dev/packages/provider_for_redux https://pub.dev/packages/provider_for_redux
Extensive documentation is available.有大量文档可用。
https://www.fireship.io has some interesting content as well regarding state management. https://www.fireship.io也有一些关于 state 管理的有趣内容。
You can use bloc package to handle the state of a subtree (in this case with Menu as root)您可以使用bloc package 来处理子树的 state(在这种情况下,菜单作为根)
Here an example:这里有一个例子:
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);
}
}
If you need to do something anywhere in the subtree when you click on a MenuIcon, you can use a BlocListener that triggers every time the state changes如果您需要在单击 MenuIcon 时在子树中的任何位置执行某些操作,则可以使用 BlocListener 每次 state 更改时触发
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.