我是新来的扑动,我一直在努力做一个非常基本的例子:在运行时从黑暗到明亮改变主题。
到目前为止,它使用ChangeNotifier
工作,但现在我想在启动时初始化我的_isDarkMode
变量,通过使用SharedPreferences
。
我的解决方案感觉像一个hack,是完全错误的:它似乎从首选项加载,但最终的结果是总是黑暗的模式。
这就是我所做的。首先,我用init
函数修改了这个类,并添加了对SharedPreferences
的必要调用:
class PreferencesModel extends ChangeNotifier {
static const _darkModeSetting = "darkmode";
bool _isDarkMode = true; // default, overridden by init()
bool get isDarkMode => _isDarkMode;
ThemeData get appTheme => _isDarkMode ? AppThemes.darkTheme : AppThemes.lightTheme;
void init() async {
final prefs = await SharedPreferences.getInstance();
final bool? dark = prefs.getBool(_darkModeSetting);
_isDarkMode = dark ?? false;
await prefs.setBool(_darkModeSetting, _isDarkMode);
}
void setDarkMode(bool isDark) async {
print("setting preferences dark mode to ${isDark}");
final prefs = await SharedPreferences.getInstance();
await prefs.setBool(_darkModeSetting, isDark);
_isDarkMode = isDark;
notifyListeners();
}
}
然后,在main
中,我从ChangeNotifierProvider
的create
lambda调用init
:
void main() {
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) {
var prefs = PreferencesModel();
prefs.init(); // overrides dark mode
return prefs;
})
],
child: const MyApp(),
)
);
}
创建MaterialApp
的State
基于首选项初始化ThemeMode
:
class _MyAppState extends State<MyApp> {
@override
Widget build(BuildContext context) {
return Consumer<PreferencesModel>(
builder: (context, preferences, child) {
return MaterialApp(
title: 'MyApp',
home: MainPage(title: 'MyApp'),
theme: AppThemes.lightTheme,
darkTheme: AppThemes.darkTheme,
themeMode: preferences.isDarkMode ? ThemeMode.dark : ThemeMode.light,
);
}
);
}
}
当然,如果我改变设置页面中的设置(在ToggleButton
处理程序上使用preferences.setDarkMode(index == 1);
),它可以工作,在运行时从亮到暗再变回来。初始化是完全错误的。
我在这里错过了什么?
我破例地回答了自己的问题。
解决方案是将首选项读取移动到主,将main改为async首先,PreferencesModel
应该有一个设置初始暗模式的构造函数:
class PreferencesModel extends ChangeNotifier {
static const darkModeSetting = "darkmode";
PreferencesModel(bool dark) {
_isDarkMode = dark;
}
bool _isDarkMode = true;
// ...
则main
功能可以为async
,正确使用共享首选项,将暗模式传递给PreferencesModel
:
void main() async {
WidgetsFlutterBinding.ensureInitialized();
final prefs = await SharedPreferences.getInstance();
final bool dark = prefs.getBool(PreferencesModel.darkModeSetting) ?? false;
print("main found dark as ${dark}");
runApp(
MultiProvider(
providers: [
ChangeNotifierProvider(create: (context) => PreferencesModel(dark))
],
child: const RecallableApp(),
)
);
}
请注意WidgetsFlutterBinding.ensureInitialized();
调用,否则共享首选项将不起作用,应用程序崩溃。