Changing the theme from light to dark in the settings does not reflecting in the app unless the app is reopened in Flutter

885

To make the logic you need, I might go using this method.

First of all - let's create a widget that will notify us about the system brightness change.
In order to change the system brightness - the user will need to close/put to background our app, do the changes in the settings and go back in to our app.
This is the place where we want to actually check if the brightness did change from the last time (when the app comes to foreground).

class BrightnessNotifier extends StatefulWidget {
  final Widget child;
  final VoidCallback? onBrightnessChanged;

  const BrightnessNotifier({
    Key? key,
    required this.child,
    this.onBrightnessChanged,
  }) : super(key: key);

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

class _BrightnessNotifierState extends State<BrightnessNotifier>
    with WidgetsBindingObserver {
  late Brightness _currentBrightness;

  @override
  void initState() {
    _currentBrightness = SchedulerBinding.instance!.window.platformBrightness; // Save initial system brightness
    WidgetsBinding.instance
        ?.addObserver(this); // Bind to app system state events
    super.initState();
  }

  @override
  void dispose() {
    WidgetsBinding.instance
        ?.removeObserver(this); // Don't forget to remove the observer
    super.dispose();
  }

  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      // App went back to foreground
      final systemBrightness = SchedulerBinding.instance!.window.platformBrightness; // Check if current system brightness did change
      if (_currentBrightness != systemBrightness) {
        _currentBrightness = systemBrightness;
        // Notify if it did
        widget.onBrightnessChanged?.call();
      }
    }
  }

  @override
  Widget build(BuildContext context) {
    return widget.child;
  }
}

After that we need to actually tell our app to re-render using the new brightness. In order to do that - we need to call build() method of our MyApp class (it will rebuild everything down the tree). To do this - we need to convert it in to a StatefulWidget and call it's setState() function to actually re-run the build() method.

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

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

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return BrightnessNotifier(
      onBrightnessChanged: () {
        setState(() {}); // Call this to re-build the widget
      },
      child: MaterialApp(
        title: 'Flutter Demo',
        debugShowCheckedModeBanner: false,
        theme: ThemeData.light(),
        darkTheme: ThemeData.dark(),
        themeMode: ThemeMode.system,
        home: SplashScreen(),
      ),
    );
  }
}

You can also put the same logic in to your MyApp widget but it would make it too bulky and hard to read.

Share:
885
viki
Author by

viki

Updated on December 17, 2022

Comments

  • viki
    viki over 1 year

    I have tried to implement the dark and light theme in my flutter app. The code is below:

    class MyApp extends StatelessWidget {
      // This widget is the root of your application.
      @override
      Widget build(BuildContext context) {
        return MaterialApp(
          title: 'Flutter Demo',
          debugShowCheckedModeBanner: false,
          theme: ThemeData.light(),
          darkTheme: ThemeData.dark(),
          themeMode: ThemeMode.system,
          home: SplashScreen(),
        );
      }
    }
    

    During runtime, I tried to change the theme from dark to light in the settings. But the theme change is not getting reflected in the app at that time. It is only updated after restarting the application. I have checked this on my Android phone. Is there anything I can do to update the theme during runtime?

  • viki
    viki almost 3 years
    Your answer worked well!! During Debugging, the theme was not updating. So, I stopped debugging and then restarted the app.
  • Thepeanut
    Thepeanut almost 3 years
    @viki hot reload does not trigger state changes and updates (it just triggers widget re-rendering), so you need to do full reload (not necessary a full app recompilation)
  • viki
    viki almost 3 years
    I meant like the theme switching was not happening during Debug mode. I had to stop debugging to make it work.