Home > Software engineering >  How to rebuild flutter Widget on Singelton value change
How to rebuild flutter Widget on Singelton value change

Time:07-09

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.

  • Related