使用 shared_preferences 在启动时获取主题
Use shared_preferences to get theme at startup
如果对 shared_preferences
的所有调用都是异步的,我如何根据存储在 shared_preferences
中的内容设置我的应用程序的主题?
例如,我有一个 ThemeService
从 shared_preferences
和 returns 中查找设置的主题,这适用于在 UI 中切换它,但我如何在启动时加载它?
class ThemeService {
static String key = "isDark";
/// Return the ThemeData based on what is persisted.
Future<ThemeData> getTheme() async {
final prefs = await SharedPreferences.getInstance();
final isDarkMode = prefs.getBool(key) ?? false;
if (isDarkMode) {
return ThemeDark().theme;
} else {
return ThemeLight().theme;
}
}
/// Toggle the theme between light/dark and persist the chosen value.
Future<void> toggleTheme() async {
final prefs = await SharedPreferences.getInstance();
final isDarkMode = prefs.getBool(key) ?? false;
if (isDarkMode) {
Get.changeTheme(ThemeLight().theme);
await prefs.setBool(key, false);
} else {
Get.changeTheme(ThemeDark().theme);
await prefs.setBool(key, true);
}
}
}
我希望能够这样使用它:
class App extends StatelessWidget {
final ThemeService themeService = Get.find<ThemeService>();
@override
Widget build(BuildContext context) {
return GetMaterialApp(
debugShowCheckedModeBanner: false,
initialBinding: InitialBinding(),
initialRoute: initialRoute(),
theme: themeService.getTheme(), // Its a future, so can't do this...
getPages: AppPages.routes);
}
}
Flutter 新手,我是不是错过了一个概念或模式?有什么方法我应该访问不需要 async/await
的首选项吗?
如评论中所建议,解决方案是将 GetMaterialApp
包装在 FutureBuilder
中
@override
Widget build(BuildContext context) {
return FutureBuilder<ThemeData>(
future: ThemeService().getTheme(),
builder: (BuildContext context, AsyncSnapshot<ThemeData> snapshot) {
return GetMaterialApp(
debugShowCheckedModeBanner: false,
initialBinding: InitialBinding(),
initialRoute: initialRoute(),
theme: snapshot.data,
darkTheme: darkTheme,
getPages: AppPages.routes);
});
}
我个人会让 main
异步。所以代码会更像:
void main() async {
final themeService = ThemeService();
final initialTheme = await themeService.getTheme();
runApp(App(initialTheme: initialTheme));
}
class App extends StatelessWidget {
final ThemeData initialTheme;
const App({Key? key, this.initialTheme}) : super(key: key);
@override
Widget build(BuildContext context) {
return GetMaterialApp(
debugShowCheckedModeBanner: false,
initialBinding: InitialBinding(),
initialRoute: initialRoute(),
theme: initialTheme, // <-- Now can do it
getPages: AppPages.routes);
}
}
如果对 shared_preferences
的所有调用都是异步的,我如何根据存储在 shared_preferences
中的内容设置我的应用程序的主题?
例如,我有一个 ThemeService
从 shared_preferences
和 returns 中查找设置的主题,这适用于在 UI 中切换它,但我如何在启动时加载它?
class ThemeService {
static String key = "isDark";
/// Return the ThemeData based on what is persisted.
Future<ThemeData> getTheme() async {
final prefs = await SharedPreferences.getInstance();
final isDarkMode = prefs.getBool(key) ?? false;
if (isDarkMode) {
return ThemeDark().theme;
} else {
return ThemeLight().theme;
}
}
/// Toggle the theme between light/dark and persist the chosen value.
Future<void> toggleTheme() async {
final prefs = await SharedPreferences.getInstance();
final isDarkMode = prefs.getBool(key) ?? false;
if (isDarkMode) {
Get.changeTheme(ThemeLight().theme);
await prefs.setBool(key, false);
} else {
Get.changeTheme(ThemeDark().theme);
await prefs.setBool(key, true);
}
}
}
我希望能够这样使用它:
class App extends StatelessWidget {
final ThemeService themeService = Get.find<ThemeService>();
@override
Widget build(BuildContext context) {
return GetMaterialApp(
debugShowCheckedModeBanner: false,
initialBinding: InitialBinding(),
initialRoute: initialRoute(),
theme: themeService.getTheme(), // Its a future, so can't do this...
getPages: AppPages.routes);
}
}
Flutter 新手,我是不是错过了一个概念或模式?有什么方法我应该访问不需要 async/await
的首选项吗?
如评论中所建议,解决方案是将 GetMaterialApp
包装在 FutureBuilder
@override
Widget build(BuildContext context) {
return FutureBuilder<ThemeData>(
future: ThemeService().getTheme(),
builder: (BuildContext context, AsyncSnapshot<ThemeData> snapshot) {
return GetMaterialApp(
debugShowCheckedModeBanner: false,
initialBinding: InitialBinding(),
initialRoute: initialRoute(),
theme: snapshot.data,
darkTheme: darkTheme,
getPages: AppPages.routes);
});
}
我个人会让 main
异步。所以代码会更像:
void main() async {
final themeService = ThemeService();
final initialTheme = await themeService.getTheme();
runApp(App(initialTheme: initialTheme));
}
class App extends StatelessWidget {
final ThemeData initialTheme;
const App({Key? key, this.initialTheme}) : super(key: key);
@override
Widget build(BuildContext context) {
return GetMaterialApp(
debugShowCheckedModeBanner: false,
initialBinding: InitialBinding(),
initialRoute: initialRoute(),
theme: initialTheme, // <-- Now can do it
getPages: AppPages.routes);
}
}