我目前正在开发一个应用程序,我已经实现了黑暗模式。当我将其从浅色模式切换到深色模式时,一切正常。当我从深色模式切换回浅色模式时,问题就开始了。我在应用程序中添加的所有原色和主题配置都丢失了。
这是我的应用程序启动时的代码:
class TradeWixApp extends StatelessWidget {
bool darkMode;
TradeWixApp({Key? key, required this.darkMode}) : super(key: key);
@override
Widget build(BuildContext context) {
return GetMaterialApp(
translations: Languages(),
locale: Locale('en'),
debugShowCheckedModeBanner: false,
darkTheme: ThemeData(
textTheme: TextTheme(
titleMedium: TextStyle(color: Colors.white70),
bodyMedium: TextStyle(color: Colors.white70),
),
shadowColor: Colors.grey.shade900,
brightness: Brightness.dark,
backgroundColor: Colors.black,
scaffoldBackgroundColor: Color.fromARGB(255, 37, 36, 36),
appBarTheme: AppBarTheme(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(20),
bottomRight: Radius.circular(20),
)),
color: Color.fromARGB(200, 174, 242, 135),
elevation: 0,
foregroundColor: Colors.black,
),
primaryColor: Color.fromARGB(200, 174, 242, 135),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
primary: Colors.black,
elevation: 0,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(20)),
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(primary: Colors.grey),
),
),
themeMode: darkMode ? ThemeMode.dark : ThemeMode.light,
theme: ThemeData(
backgroundColor: Colors.white,
scaffoldBackgroundColor: Colors.white,
appBarTheme: AppBarTheme(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(20),
bottomRight: Radius.circular(20),
)),
color: Color.fromARGB(255, 174, 242, 135),
elevation: 0,
foregroundColor: Colors.black,
),
primaryColor: Color.fromARGB(255, 174, 242, 135),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
primary: Colors.black,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20)),
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(primary: Colors.grey),
)),
home: const SplashScreen(),
);
}
}
我切换暗模式的代码是:
Obx(() {
return ListTile(
title: Text('Dark Mode'.tr),
trailing: Switch(
value: darkMode.value,
onChanged: (value) async {
darkMode.value = value;
Get.changeTheme(
!value ? ThemeData.light() : ThemeData.dark());
Get.changeThemeMode(
!value ? ThemeMode.light : ThemeMode.dark);
Get.reloadAll();
final prefs = await SharedPreferences.getInstance();
await prefs.setBool('darkMode', value);
},
));
})
我不明白为什么你在你的代码中使用
Get.changeTheme
,你已经在你的theme
上设置了darkTheme
和GetMaterialApp
,所以要在它们之间切换,你只需要调用Get.changeThemeMode
,但是这个:
Get.changeTheme( !value ? ThemeData.light() : ThemeData.dark());
ThemeData.dark()
和ThemeData.light()
是新的整体主题,我想您的目标是在浅色模式和深色模式之间切换,而不是在主题列表之间设置主题。因此,当您调用 Get.changeTheme()
时,您会将应用程序主题重置为默认浅色和深色(这会给您重置主题的行为)
尝试添加
themeMode: ThemeMode.system,
到您的 GetMaterialApp。
尝试使用
Get.changeThemeMode(ThemeMode.light);
而不是
Get.changeTheme(ThemeData.light());
我知道这可能会迟到,但我希望它可以帮助其他面临主题相关问题的人。
如果我理解正确,你希望你的应用程序保留为每种模式(深色/浅色)定义的颜色,如果你想这样做,你可能需要更有效地定义你的颜色,并使用我在我的一篇文章中学到的一个很棒的技巧。在 Flutter 中试验 Material 3 的项目。
通过这种方式,您可以向应用程序添加任意数量的主题,并且能够随时编辑颜色并在所有应用程序小部件中查看它们的反映。 请注意,您不必再为小部件提供 color/backgroundColor 属性,因为颜色是从该文件推断出来的,但如果您遇到定义的主题不适合您的需求的特定情况,您始终可以使用这些属性一些特定的小部件。
此代码片段是我的整个主题文件,其中有两个主题(浅色和深色),带有自定义字体和从应用程序 Figma 设计中复制的定义颜色。
import 'package:flutter/material.dart';
class AppTheme {
static const darkTheme = ColorScheme.dark(
primary: Color(0xFFF8D028),
onPrimary: Color(0xFF333333),
primaryContainer: Color(0xFFD0C000),
onPrimaryContainer: Color(0xFF333333),
secondary: Color(0xFF3B9DFF),
onSecondary: Color(0xFFF3F3F3),
secondaryContainer: Color(0xFFF0A000),
onSecondaryContainer: Color(0xFF333333),
error: Colors.redAccent,
onError: Colors.red,
errorContainer: Colors.redAccent,
onErrorContainer: Color(0xFFF9DEDC),
outline: Color(0xFF938F99),
background: Color(0xFF333333),
onBackground: Color(0xFFF3F3F3),
surface: Color(0xFF333333),
onSurface: Color(0xFFF3F3F3),
surfaceVariant: Color(0xFF49454F),
onSurfaceVariant: Color(0xFFCAC4D0),
);
static ColorScheme lightTheme = ColorScheme.light(
primary: const Color(0xFFF8D028),
onPrimary: const Color(0xFF333333),
primaryContainer: const Color(0xFFFDD943),
onPrimaryContainer: const Color(0xFF333333),
secondary: const Color(0xFF3B9DFF),
onSecondary: const Color(0xFFF3F3F3),
secondaryContainer: Colors.amber.shade700,
onSecondaryContainer: const Color(0xFF333333),
error: Colors.redAccent,
onError: Colors.red,
errorContainer: Colors.redAccent,
onErrorContainer: const Color(0xFFF9DEDC),
outline: const Color(0xFF6F6D73),
background: const Color(0xFFF3F3F3),
onBackground: const Color(0xFF333333),
surface: const Color(0xFFFDCC34),
onSurface: const Color(0xFF333333),
surfaceVariant: const Color(0xFF57545B),
onSurfaceVariant: const Color(0xFF757575),
);
static final light = ThemeData(
useMaterial3: true,
fontFamily: 'Poppins',
colorScheme: lightTheme,
);
static final dark = ThemeData(
useMaterial3: true,
fontFamily: 'Poppins',
colorScheme: darkTheme,
);
}
这是我使用 GetX 的 ThemeController 文件。 注意:我使用 get_storage 包在应用程序重新启动时保留我的主题状态,如果这是我第一次运行应用程序,则默认值为 false。
import 'package:get/get.dart';
import 'package:get_storage/get_storage.dart';
import 'app_theme.dart';
class ThemeController extends GetxController {
final box = GetStorage();
RxBool isDarkMode = false.obs;
@override
void onInit() {
super.onInit();
isDarkMode.value = box.read('isDarkMode') ?? false;
}
void toggleTheme() {
isDarkMode.value = !isDarkMode.value;
Get.changeTheme(
isDarkMode.value ? MyFeedbackTheme.dark : MyFeedbackTheme.light,
);
box.write('isDarkMode', isDarkMode.value);
}
}
不要忘记将其与您的 MaterialApp 或 GetMaterialApp 合并,因为在这样做之前我们的逻辑仍然无法运行。
main.dart
// rest of code
return GetMaterialApp(
textDirection: Get.find<LocaleController>().currentLang == 'ar'
? TextDirection.rtl
: TextDirection.ltr,
translations: AppLocale(),
locale: Get.find<LocaleController>().initLang,
fallbackLocale: Get.find<LocaleController>().initLang,
title: 'App Name',
theme: AppTheme.light,
darkTheme: AppTheme.dark,
themeMode: Get.find<ThemeController>().isDarkMode.value
? ThemeMode.dark
: ThemeMode.light,
home: const WelcomeScreen(),
);
// rest of code
这样你的主题切换逻辑就完成了,你所要做的就是使用你选择的小部件来使用它,在我的例子中,我使用了带有 GetX Obx 的 Switch 小部件,就像你所做的那样
这是代码片段
// rest of code
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text("Theme".tr),
Obx(
() => Switch(
value: themeController.isDarkMode.value,
onChanged: (value) => themeController.toggleTheme(),
activeTrackColor: kPrimaryColor.withOpacity(0.1),
activeColor: kPrimaryColor,
inactiveThumbColor: kPrimaryColor,
thumbIcon: MaterialStateProperty.resolveWith<Icon?>(
(Set<MaterialState> states) {
if (states.contains(MaterialState.selected)) {
return const Icon(Icons.brightness_2);
}
return null; // All other states will use the default thumbIcon.
}),
),
),
],
),
),
// rest of code
这就是开关的样子,如果您不喜欢它,则不必尝试该代码
深色模式状态
灯光模式状态
我共享的文件(包含 AppTheme 类的文件和包含 ThemeController 的文件)在每个应用程序中保持不变,您只需更改您的调色板并准备好即可。
我还没有在默认的 Material 2 上尝试过这些选项,所以我不知道它是否适合每个人,并且不要在开发过程中将应用程序从 M2 更改为 M3,因为它可能会搞乱您的应用程序的外观。如果您刚刚启动一个新的应用程序,我只建议其他人使用此方法。但是,如果您准备好解决开发过程中从 M2 切换到 M3 引起的问题,我相信这种方法将大大节省您的时间和精力,特别是如果您的应用程序使用 >= 2 个主题。
希望这有帮助:)