Search code examples
flutterdartflutter-provider

Flutter Convert Switch


I am building a website on flutter and want to add functionality to swap between light and dark themes. I have achieved this goal using a switch that swaps between the themes however I want to replace the switch itself with an icon that will swap as the themes swap.

I have the following:

In the appbar:

actions: const [
            ChangeThemeButtonWidget(),
          ],

In the ChangeThemeButtonWidget()

class ChangeThemeButtonWidget extends StatelessWidget {
  const ChangeThemeButtonWidget({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final themeProvider = Provider.of<ThemeProvider>(context);

    return Switch.adaptive(
      value: themeProvider.isDarkMode,
      onChanged: (value) {
        final provider = Provider.of<ThemeProvider>(context, listen: false);
        provider.toggleTheme(value);
      },
    );
  }
}

and within my themeprovider

class ThemeProvider with ChangeNotifier {
  ThemeMode themeMode = ThemeMode.light;
  bool get isDarkMode => themeMode == ThemeMode.dark;

  void toggleTheme(bool isOn) {
    themeMode = isOn ? ThemeMode.dark : ThemeMode.light;
    notifyListeners();
  }
}

The issue comes when I attempt to replace the switch with a button, no matter what I use It does not trigger a change. Ideally I would like to use a button using the Icons.light_mode and Icons.dark_mode, I already know how to swap them based on the theme I just can't figure out how to have the button trigger the swap.

Many thanks for any assistance!

Edit: Material app:

void main() {
  runApp(App());
}

class App extends StatelessWidget {
  const App({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) => ChangeNotifierProvider(
        create: (context) => ThemeProvider(),
        builder: (context, _) {
          final themeprovider = Provider.of<ThemeProvider>(context);
          return MaterialApp(
            debugShowCheckedModeBanner: false,
            title: "Test",
            // onGenerateTitle: (BuildContext context) =>
            //     AppLocalizations.of(context)!.appTitle,
            themeMode: themeprovider.themeMode,
            theme: MyThemes.lightTheme,
            darkTheme: MyThemes.darkTheme,
            routes: appRoutes,
          );
        },
      );
}

Solution

  • Make sure to have different themes on two modes. You can follow this snippet.

    class ChangeThemeButtonWidget extends StatelessWidget {
      const ChangeThemeButtonWidget({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return IconButton(
          icon: Icon(
            Provider.of<ThemeProvider>(context).isDarkMode
                ? Icons.dark_mode
                : Icons.light_mode,
          ),
          onPressed: () {
            final provider = Provider.of<ThemeProvider>(context, listen: false);
            provider.toggleTheme(!provider.isDarkMode);
          },
        );
      }
    }