I am trying to rebuild a stateful widget every time a value in my global Singelton is changed but I'm stumped.
My goal is to rebuild my Cart Icon every time the cartSize is changed throughout my app.
I know I need to send out a notification whenever the Singelton cartSize
value is changed. and listen for that notification in my stateful widget but how do I do this?
Any help is greatly appreciated.
My Global Singelton
library #######.globals;
import 'package:flutter/material.dart';
class GlobalSingleton extends ChangeNotifier {
static final GlobalSingleton _instance = GlobalSingleton._internal();
// passes the instantiation to the _instance object
factory GlobalSingleton() {
return _instance;
}
//initialize variables in here
GlobalSingleton._internal() {
cartSize = 0;
}
late int cartSize;
}
My stateful Widget
import 'package:######/globals/globals.dart';
import 'package:flutter/material.dart';
class BuildMarketplaceCartIcon extends StatefulWidget {
const BuildMarketplaceCartIcon({Key? key}) : super(key: key);
@override
State<BuildMarketplaceCartIcon> createState() =>
_BuildMarketplaceCartIconState();
}
class _BuildMarketplaceCartIconState extends State<BuildMarketplaceCartIcon> {
CRUDMarketplaceCart localCartData = CRUDMarketplaceCart();
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {
},
child: Container(
width: 72,
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Stack(
alignment: Alignment.center,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Icon(Icons.shopping_cart),
Text(
'Cart',
overflow: TextOverflow.ellipsis,
),
],
),
Positioned(
top: 0,
right: 0,
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 6,
vertical: 2,
),
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
),
alignment: Alignment.center,
child: Text(
'${globals.GlobalSingleton().cartSize}',
),
),
),
],
),
),
);
}
}
CodePudding user response:
When using ChangeNotifier
you need to call notifyListeners
when the value changes. You also need to have your widget listen to the ChangeNotifier
, so that it knows when to rebuild.
The most common way to go about that is to use the provider package, which includes the ChangeNotifierProvider
widget.
Using provider, your code would look something like this:
class GlobalSingleton extends ChangeNotifier {
static final GlobalSingleton _instance = GlobalSingleton._internal();
// passes the instantiation to the _instance object
factory GlobalSingleton() {
return _instance;
}
//initialize variables in here
GlobalSingleton._internal() {
_cartSize = 0;
}
late int _cartSize;
int get cartSize => _cartSize;
void set cartSize(int newCartSize) {
_cartSize = newCartSize;
notifyListeners();
}
}
Here, we update your singleton so that it will call notifyListeners()
whenever the cartSize is set.
Next you'll need to update your widget to listen to the changes:
import 'package:######/globals/globals.dart';
import 'package:flutter/material.dart';
class BuildMarketplaceCartIcon extends StatefulWidget {
const BuildMarketplaceCartIcon({Key? key}) : super(key: key);
@override
State<BuildMarketplaceCartIcon> createState() =>
_BuildMarketplaceCartIconState();
}
class _BuildMarketplaceCartIconState extends State<BuildMarketplaceCartIcon> {
CRUDMarketplaceCart localCartData = CRUDMarketplaceCart();
@override
Widget build(BuildContext context) {
return InkWell(
onTap: () {},
child: Container(
width: 72,
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Stack(
alignment: Alignment.center,
children: [
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const <Widget>[
Icon(Icons.shopping_cart),
Text(
'Cart',
overflow: TextOverflow.ellipsis,
),
],
),
Positioned(
top: 0,
right: 0,
child: Container(
padding: const EdgeInsets.symmetric(
horizontal: 6,
vertical: 2,
),
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Colors.white,
),
alignment: Alignment.center,
child: ChangeNotifierProvider.value(
value: GlobalSingleton(),
child: Consumer<GlobalSingleton>(
builder: (context, singleton, child) {
return Text(
'${singleton.cartSize}',
);
},
),
),
),
),
],
),
),
);
}
}
Here I put the Provider
widget as directly enclosing the Consumer
widget - however, if you need the singleton's value in more than one place, you can put the Provider
higher up the widget tree so that it's a common ancestor of any Consumer
that listens to changes in the singleton.