1

I've got a flutter app that has a theme switcher that isn't working right. The app's state is built as:

class XKCDRandomizerAppState extends State<XKCDRandomizerApp> {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: widget.title,
      theme: CustomTheme.currentTheme,
      debugShowCheckedModeBanner: false,
      home: const IntroPage(),
    );
  }
}

The CustomTheme class has two static methods returning ThemeData (light or dark):

class CustomTheme {
  static var currentTheme = lightTheme;

  static ThemeData get lightTheme {
    return ThemeData(
      brightness: Brightness.light,
      primaryColor: Colors.green,
      colorScheme: ColorScheme.fromSwatch().copyWith(
        primary: Colors.green,
        secondary: Colors.greenAccent,
        brightness: Brightness.light,
        background: Colors.white70,
      ),
    );
  }
  [snip]

It also has a static variable called currentTheme that I'm setting as the MaterialApp's theme. I'm changing it in setState() method calls in onTap() methods of two ChoiceChips in IntroPage (home of MaterialApp), also stateful. In it's build():

[snip]
child: ChoiceChip(
  selected: CustomTheme.currentTheme == CustomTheme.lightTheme,
  label: const Text("light"),
  backgroundColor: Colors.green,
  labelStyle: const TextStyle(color: Colors.black),
  onSelected: (bool selected) {
    setState(
      () {
        print(CustomTheme.currentTheme == CustomTheme.darkTheme);
        CustomTheme.currentTheme = CustomTheme.lightTheme;
        print(CustomTheme.currentTheme == CustomTheme.lightTheme);
      },
    );
  },
),
[snip]

When I click the ChoiceChips I print out the currentTheme info, e.g. the above prints out true and true - currentTheme is being switched but the MaterialApp theme doesn't get refreshed. If I change nothing while running but click Save in Android Studio the app updates. What am I doing wrong?

CraigFoote
  • 371
  • 1
  • 7
  • 23

1 Answers1

0

Based on this post, I implemented a callback that works. I'll post the details in case it helps someone.

Here's the callback in the same class as MaterialWidget so that setState() refreshes it:

class XKCDRandomizerAppState extends State<XKCDRandomizerApp> {
  void themeCallback(value) {
    setState(() => CustomTheme.currentTheme = value);
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: widget.title,
      theme: CustomTheme.currentTheme,
      debugShowCheckedModeBanner: false,
      home: IntroPage(themeCallback),
    );
  }
}

Here's the IntroPage with the received callback param:

class IntroPage extends StatefulWidget {
  const IntroPage(this.themeCallback, {Key? key}) : super(key: key);

  final Function(ThemeData) themeCallback;

  @override
  State<StatefulWidget> createState() => IntroPageState();
}

Here's the ChoiceChip calling the callback now in its widget:

[snip]
child: ChoiceChip(
   selected: CustomTheme.currentTheme == CustomTheme.lightTheme,
   label: const Text("light"),
   backgroundColor: Colors.black12,
   labelStyle: const TextStyle(color: Colors.orange),
   onSelected: (bool selected) {
     setState(
       () {
         widget.themeCallback(CustomTheme.lightTheme);
        },
     );
   },
 ),
[snip]
CraigFoote
  • 371
  • 1
  • 7
  • 23