Light / Dark Mode in flutter

2,125

When calling Provider.of on a button, you should always pass listen: false, like so:

onChanged: (value) {
  Provider.of<ThemeState>(context, listen: false).theme =
    value ? ThemeType.DARK : ThemeType.LIGHT;
    setState(() {});
})

To be completely honest, I'm not sure if this will fix your code, however when I tried to replicate your error, I got the following error message:

════════ Exception caught by gesture ═══════════════════════════════════════════
Tried to listen to a value exposed with provider, from outside of the widget tree.

This is likely caused by an event handler (like a button's onPressed) that called
Provider.of without passing `listen: false`.

Here's my minimal example, which worked after adding listen: false

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(ChangeNotifierProvider<MyValue>(
    create: (context) => MyValue(true),
    child: MyApp(),
  ));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key}) : super(key: key);

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: Checkbox(
          value: Provider.of<MyValue>(context).value,
          onChanged: (val) {
            Provider.of<MyValue>(context, listen: false).value = val!;
            setState(() {});
          },
        ),
      ),
    );
  }
}

class MyValue extends ChangeNotifier {
  MyValue(this.value);
  bool value;
}

So I hope adding listen: false will solve your problem

Share:
2,125
Berfin Gürz
Author by

Berfin Gürz

Updated on January 01, 2023

Comments

  • Berfin Gürz
    Berfin Gürz over 1 year

    I want to put the light/dark mode switch inside the application. Switch is okay. But it isn't any changing in application. Just I see the light theme. And, when I clicked the switch, I get this error or warning (idk). : Another exception was thrown: Tried to listen to a value exposed with provider, from outside the widget tree.

    This is the main.dart:

        import 'package:provider/provider.dart';
        import 'package:bankingapp/widget/themestate.dart';
        
        void main() {
          runApp(ChangeNotifierProvider<ThemeState>(
            create: (context) => ThemeState(),
            child: MyApp(),
          ));
        }
    
        class MyApp extends StatelessWidget {
          // This widget is the root of your application.
          @override
          Widget build(BuildContext context) {
            return MaterialApp(
              theme: Provider.of<ThemeState>(context).theme == ThemeType.DARK
                  ? ThemeData.dark()
                  : ThemeData.light(),
              debugShowCheckedModeBanner: false,
              home: MySplash(),
            );
          }
        }
    

    This is the homescreen.dart:

    Container(
      child: Switch(
        value: Provider.of<ThemeState>(context).theme == ThemeType.DARK,
        onChanged: (value) {
          Provider.of<ThemeState>(context).theme =
              value ? ThemeType.DARK : ThemeType.LIGHT;
          setState(() {});
        },
      ),
    ),
    

    This is the themestate.dart:

    import 'package:flutter/material.dart';
    
    enum ThemeType { DARK, LIGHT }
    
    class ThemeState extends ChangeNotifier {
      bool _isDarkTheme = false;
    
      ThemeState() {
        getTheme().then((type) {
          _isDarkTheme = type == ThemeType.DARK;
          notifyListeners();
        });
      }
      ThemeType get theme => _isDarkTheme ? ThemeType.DARK : ThemeType.LIGHT;
      set theme(ThemeType type) => setTheme(type);
    
      void setTheme(ThemeType type) async {
        _isDarkTheme = type == ThemeType.DARK;
        notifyListeners();
      }
    
      Future<ThemeType> getTheme() async {
        return _isDarkTheme ? ThemeType.DARK : ThemeType.LIGHT;
      }
    }
    

    Note: This code snippet is the part of the project about ThemeS. Because code is consisted of very long line.