Reputation: 27
I want to send data from widget to another widget, in my example i want to send some filter data from FilterScreen.dart to ShopScreen.dart it works fine but i dont know is what i'm doing is correct?
in filter model file:
class FilterData with ChangeNotifier {
bool isFreeShipping;
bool isSomeThingElse;
FilterData({this.isFreeShipping = false, this.isSomeThingElse = false});
void setFreeShippingValue(bool newval) {
isFreeShipping = newval;
notifyListeners();
}
void setSomeThingElseValue(bool newval) {
isSomeThingElse = newval;
notifyListeners();
}
}
in main.dart:
return ChangeNotifierProvider(
create: (context) => FilterData(),
child: MaterialApp(
.........
)
);
in tabs screen:
class TabsScreen extends StatefulWidget {
@override
_TabsScreenState createState() => _TabsScreenState();
}
class _TabsScreenState extends State<TabsScreen> {
List<Map<String, Object>> _pages;
int _selectedPageIndex = 0;
@override
void initState() {
_pages = [
{
'page': ShopScreen(),
'title': 'shop',
},
{
'page': FilterScreen(),
'title': 'filter',
},
];
super.initState();
}
void _selectPage(int index) {
setState(() {
_selectedPageIndex = index;
});
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_pages[_selectedPageIndex]['title']),
),
drawer: DrawerApp(),
body: _pages[_selectedPageIndex]['page'],
bottomNavigationBar: BottomNavigationBar(
onTap: _selectPage,
backgroundColor: Theme.of(context).primaryColor,
unselectedItemColor: Colors.white,
selectedItemColor: Theme.of(context).accentColor,
currentIndex: _selectedPageIndex,
// type: BottomNavigationBarType.fixed,
items: [
BottomNavigationBarItem(
backgroundColor: Theme.of(context).primaryColor,
icon: Icon(Icons.shop),
title: Text('Shop'),
),
BottomNavigationBarItem(
backgroundColor: Theme.of(context).primaryColor,
icon: Icon(Icons.search),
title: Text('Filter'),
),
],
),
);
}
}
in FilterScreen.dart:
class FilterScreen extends StatefulWidget {
@override
_FilterScreenState createState() => _FilterScreenState();
}
class _FilterScreenState extends State<FilterScreen> {
@override
Widget build(BuildContext context) {
final data = Provider.of<FilterData>(context);
return Container(
child: Center(
child: Expanded(
child: ListView(
children: <Widget>[
SwitchListTile(
title: Text('Free Shipping'),
value: data.isFreeShipping,
subtitle: Text('get free shipping products'),
onChanged: (newValue) {
data.setFreeShippingValue(newValue);
}),
SwitchListTile(
title: Text('Some thing else'),
value: data.isSomeThingElse,
subtitle: Text('get filtred products'),
onChanged: (newValue) {
data.setSomeThingElseValue(newValue);
}),
],
),
),
),
);
}
}
in ShopScreen.dart:
class ShopScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final data = Provider.of<FilterData>(context);
return Container(
child: Center(
child: Text(
data.isFreeShipping ? 'get favorite Products' : 'get all products'),
),
);
}
}
Upvotes: 0
Views: 1097
Reputation: 8978
Your question indeed is a pain for most of the developers, which is like I don't know how it works!
So, if you are not able to understand. there are two reasons to that:
Flutter Provider State Management works
. So, for that, do read upon these:
So, now let us jump to the code. How your code works?
There are multiple things which are responsible for this:
1. Provider Wrap: If you closely look into the main.dart
code, you have done this
return ChangeNotifierProvider(
create: (context) => FilterData(), // here you define the ChangeNotifier class
child: MaterialApp(
.........
)
);
Now looking at the above code, you see, whenever you wrap the app with the ChangeNotifierProvider()
, it always rebuilds whenever there is a state change in the class which you have provided inside that, in this case FilterData()
. Any changes happens will reflect in the whole app, because ChangeNotifierProvider()
, is keep rebuilding the state of the immediate child, in this case your, MaterialApp()
, which is wrapped.
2. NotifyChanges from the ChangeNotifier class: If you look at your FilterData
, it is the one which is responsible for the rebuilding of the app, which is wrapped by the ChangeNotifierProvider()
.
Let us see how:
void setFreeShippingValue(bool newval) {
isFreeShipping = newval;
notifyListeners();
}
void setSomeThingElseValue(bool newval) {
isSomeThingElse = newval;
notifyListeners();
}
If you closely take a look at the methods, which I mentioned in the above code from your FilterData
class only, they have notifyListeners()
. These are the ones, which is responsible, whenever your two methods called, it notifies the ChangeNotifierListener
to rebuild the widget, and hence you see the updated data every time, you use any of the two methods
3. Using NotifyListeneres method from the FilterData in FilterScreen: So, again if we look closely at the thing which we have mentioned in the point 2, we see that, the method method should be called to make changes in the App which is the immediate child of ChangeNotifierProvider()
SwitchListTile(
title: Text('Free Shipping'),
value: data.isFreeShipping,
subtitle: Text('get free shipping products'),
onChanged: (newValue) {
data.setFreeShippingValue(newValue);
}),
SwitchListTile(
title: Text('Some thing else'),
value: data.isSomeThingElse,
subtitle: Text('get filtred products'),
onChanged: (newValue) {
data.setSomeThingElseValue(newValue);
}),
So, when you call any of the methods in your onChanged
, it straight away notifies the Provider that, the value has been changed, and the app rebuilds, and when you switch to the other tab, you see updated result like magic.
MOST IMPORTANT: Your final data = Provider.of<FilterData>(context);
, is an instance of the Provider class, which trigger the method to help notify the ChangeNotifierProvider()
to make changes in the app
So the mapping is like that:
Listens to the change
FilterData {setFreeShippingValue, setSomeThingElseValue} <----------------------> ChangeNotifierProvider() REBUILDS MATERIALAPP()
Upvotes: 1