Flutter GetX 主题模式问题

问题描述 投票:0回答:4

我目前正在开发一个应用程序,我已经实现了黑暗模式。当我将其从浅色模式切换到深色模式时,一切正常。当我从深色模式切换回浅色模式时,问题就开始了。我在应用程序中添加的所有原色和主题配置都丢失了。

这是我的应用程序启动时的代码:


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);
                        },
                      ));
                })

这是切换前的灯

这是深色模式 这是切换后的灯光模式

flutter dart themes flutter-getx mode
4个回答
2
投票

我不明白为什么你在你的代码中使用

Get.changeTheme
,你已经在你的
theme
上设置了
darkTheme
GetMaterialApp
,所以要在它们之间切换,你只需要调用
Get.changeThemeMode 
,但是这个:

Get.changeTheme( !value ? ThemeData.light() : ThemeData.dark());

ThemeData.dark()
ThemeData.light()
是新的整体主题,我想您的目标是在浅色模式和深色模式之间切换,而不是在主题列表之间设置主题。因此,当您调用
Get.changeTheme()
时,您会将应用程序主题重置为默认浅色和深色(这会给您重置主题的行为)


1
投票

尝试添加

themeMode: ThemeMode.system,

到您的 GetMaterialApp。


1
投票

尝试使用

Get.changeThemeMode(ThemeMode.light);

而不是

 Get.changeTheme(ThemeData.light());

0
投票

我知道这可能会迟到,但我希望它可以帮助其他面临主题相关问题的人。

如果我理解正确,你希望你的应用程序保留为每种模式(深色/浅色)定义的颜色,如果你想这样做,你可能需要更有效地定义你的颜色,并使用我在我的一篇文章中学到的一个很棒的技巧。在 Flutter 中试验 Material 3 的项目。

TL;DR:您需要定义主题并分别为每个主题定义颜色。

长答案

通过这种方式,您可以向应用程序添加任意数量的主题,并且能够随时编辑颜色并在所有应用程序小部件中查看它们的反映。 请注意,您不必再为小部件提供 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 个主题。

希望这有帮助:)

© www.soinside.com 2019 - 2024. All rights reserved.