I would like to change the app theme according to switch button. I am using ChangeNotifier to do that.
class ThemesProvider extends ChangeNotifier {
ThemeMode themeMode = ThemeMode.system;
bool get isDarkMode => themeMode == ThemeMode.dark;
void changeTheme(bool isOn) {
themeMode = isOn ? ThemeMode.dark : ThemeMode.light;
notifyListeners();
}
}
that's the class that I am using to change the theme.
final themesProvider = ChangeNotifierProvider((_) => ThemesProvider());
class MyApp extends ConsumerWidget {
const MyApp({
super.key,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final themeModeState = ref.watch(themesProvider).themeMode;
return MaterialApp(
theme: Themes.lightTheme,
darkTheme: Themes.darkTheme,
themeMode: themeModeState,
debugShowCheckedModeBanner: false,
home: const SignInScreen(),
);
}
}
That is my main file.
final themesProvider = ChangeNotifierProvider((_) => ThemesProvider());
class MainScreen extends ConsumerWidget {
const MainScreen({
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final themeModeState = ref.watch(themesProvider);
return Scaffold(
appBar: AppBar(
title: Text("Try Me"),
leading: Consumer(
builder: (context, ref, child) {
return Switch(
value: themeModeState.isDarkMode,
onChanged: (value) {
themeModeState.changeTheme(value);
});
},
),
),
);
}
}
And this is where I try to change the theme.
I/flutter ( 4525): ThemeMode.dark
I/flutter ( 4525): ThemeMode.light
I/flutter ( 4525): ThemeMode.dark
It seems the function is working fine. I don't know where I made a mistake. Can one of you please help me to fix that.
CodePudding user response:
This short example works as expected:
void main() => runApp(const ProviderScope(child: MyApp()));
class ThemesProvider extends ChangeNotifier {
ThemeMode themeMode = ThemeMode.system;
bool get isDarkMode => themeMode == ThemeMode.dark;
void changeTheme(bool isOn) {
themeMode = isOn ? ThemeMode.dark : ThemeMode.light;
notifyListeners();
}
}
final themesProvider = ChangeNotifierProvider((_) => ThemesProvider());
class MyApp extends ConsumerWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final themeModeState = ref.watch(themesProvider).themeMode;
return MaterialApp(
theme: ThemeData.light(),
darkTheme: ThemeData.dark(),
themeMode: themeModeState,
debugShowCheckedModeBanner: false,
home: const MainScreen(),
);
}
}
class MainScreen extends ConsumerWidget {
const MainScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context, WidgetRef ref) {
final themeModeState = ref.watch(themesProvider);
return Scaffold(
appBar: AppBar(
title: Text("Try Me, current: ${themeModeState.themeMode}"),
leading: Switch(
value: themeModeState.isDarkMode,
onChanged: (value) {
themeModeState.changeTheme(value);
},
),
),
);
}
}
The problem is probably here:
...
theme: Themes.lightTheme,
darkTheme: Themes.darkTheme,
...
Or maybe you declare two different instances of ThemesProvider()
and this has some effect (I think not)
CodePudding user response:
For ChangeNotifier
and StateNotifier
, you should call functions on notifier. e.g.
ref.read(yourProvider.notifier).function()
So onChanged
function in Switch
widget have to changed to following:
onChanged: (value) {
ref.read(themesProvider.notifier).changeTheme(value);
});
Remark: You should use read
instead of watch
inside onPressed, onChanged and other functions.
It is usually not recommended to use ChangeNotifier
, but instead use StateNotifier
, which promotes immutable architecture and makes code more maintainable.