ChangeNotifier

Controlling Widgets with ChangeNotifier

When You Need to Control a Widget from Outside

State management solutions are incredibly convenient, but sometimes we need pure Flutter solutions without relying on third-party libraries.

In some cases, we have shared widgets that require a built-in state management tool from Flutter itself. This is where ChangeNotifier becomes a powerful option.

We can think of ChangeNotifier as a way to create controllers similar to familiar built-in Flutter controllers like:

Just like these, ChangeNotifier allows us to create custom controllers for widgets while keeping everything within Flutter’s ecosystem.

Quickly Implementing ChangeNotifier

Using ChangeNotifier requires initialization and writing a significant amount of code. To simplify this process, I use Mason to generate a boilerplate template for faster development.

If you're unfamiliar with Mason, check out this guide:

Mason

You can also explore my Mason template for ChangeNotifier here: 🔗 dr_change_notifier

Controller Section

This part defines the controller responsible for managing the widget’s state.

/// Part II: Controller
class {{name.pascalCase()}}Controller with ChangeNotifier implements Listenable {
  /// Learn more: url_to_document_of_package

  int _example = 0;
  int get example => _example;

  // USE | controller.example = example;
  set example(int index){
    _example = index;
    notifyListeners();
  }

  //  @override
  //   void dispose() {
  //   super.dispose();
  //
  // }
}

This section contains variables for storing data. If you want to update the screen that uses this controller, call notifyListeners(); at the end of the function. This will trigger a UI rebuild.

UI Section

This part defines how the user interface (UI) interacts with the ChangeNotifier controller.

/// Part I: Screen
class {{name.pascalCase()}} extends StatefulWidget {
  const {{name.pascalCase()}}({super.key, this.controller, this.autoDispose = true});

  final  {{name.pascalCase()}}Controller? controller;
  final bool autoDispose;

  @override
  State<{{name.pascalCase()}}> createState() => _{{name.pascalCase()}}State();
}

class _{{name.pascalCase()}}State extends State<{{name.pascalCase()}}> {

  late {{name.pascalCase()}}Controller controller;

  @override
  void initState() {
    super.initState();
    controller = widget.controller ?? {{name.pascalCase()}}Controller();
    controller.addListener(() {
      if (mounted) {
        setState(() {});
      }
    });
  }

  // update once properties is changed
  @override
  void didUpdateWidget({{name.pascalCase()}} oldWidget) {
    super.didUpdateWidget(oldWidget);
    // if (widget.path != oldWidget.path) {
    //
    // }
  }

  @override
    void dispose() {
    if(widget.autoDispose) controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {

    // final ratio = context.dsgRatio;

    return const Text("ok");
  }
}

In this UI section, I have pre-configured the following:

  • Automatic controller initialization if no controller is passed in initState().

  • Automatic disposal of the controller when the widget is destroyed in dispose().

  • Listening for notifyListeners() calls from the controller and updating the UI accordingly.

    controller.addListener(() {
      if (mounted) {
        setState(() {});
      }
    });

Real-World Usage

Real-World Usage

Assuming I have a ChangeNotifier structure for the camera as shown in the image, the initialization process will be as follows:

Step 1: Initialize the Controller

CameraWidgetController controllerCamera = CameraWidgetController();

Make sure to dispose of it when it's no longer needed.


Step 2: Initialize the UI

Initialize the UI

Pass the controller into the widget that needs to be controlled externally.

Step 3: Usage

Step 3: Usage

Now, you can use it anywhere in your project as needed.

This is my approach to controlling widgets externally. You can use this as a reference and create your own code template with Mason, customizing it to fit your coding style and preferences.

Buy Me a Coffee | Support Me on Ko-fi

Last updated