Stack Overflow Asked by Tom Ryan on January 1, 2022
I have a Menu
Stateful Widget which is a Parent Widget to multiple instances of a MenuIcon
child widget which returns a container. 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. 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. 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. 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.
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.
The code for the Menu
and MenuIcon
classes are as follows:
//----------------- 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,
);
}
}
Another viable option is the Async_Redux package available on pub.dev
It has way less boilerplate code and allows very easy state implementation. You can configure ReduxActions to manipulate state from your actions. The whole app reacts to the state manipulations. ReduxSelectors are then used to show the specific changes on every screen.
Do explore:
https://pub.dev/packages/async_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.
Answered by Hamza A.Malik on January 1, 2022
You can check the package provider, using this it is easy to manage UI in every page,
Adding some articles
Answered by Afinas EM on January 1, 2022
You can use bloc package to handle the state of a subtree (in this case with Menu as root)
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
Answered by Luca Oropallo on January 1, 2022
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP