You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter自定义明暗主题切换异常:切换显示异常重启后恢复

Flutter 自定义主题切换后显示异常,重启后恢复正常问题解决

问题描述

在Flutter中开发自定义明暗双主题,切换主题时部分颜色显示异常,但重启应用后主题显示恢复正常。

效果对比

  • 切换主题后异常显示:切换后未重启的异常显示
  • 重启应用后正常显示:重启后的正常显示

相关代码实现

主页面代码

ThemeController themecontroller = Get.put(ThemeController());
return GetMaterialApp(
    title: 'where to go',
    debugShowCheckedModeBanner: false,
    translations: Messages(),
    locale: mycontroller.initlang,
    theme: themecontroller.themedata
        ? Themes.customDarkTheme
        : Themes.customLightTheme,
    darkTheme: Themes.customDarkTheme,
    home: const SplashScreen());

自定义主题类代码

class Themes {
  static ThemeData customLightTheme = ThemeData(
      brightness: Brightness.light,
      colorScheme: ColorScheme.light(
        background: Colors.white,
        primary: Colors.white,
        onPrimary: Colors.grey[600]!,
        secondary: Colors.white,
        onSecondary: Colors.grey[600]!,
        surface: Colors.white,
        onSurface: Colors.deepPurple,
        tertiary: Colors.black,
        onTertiary: const Color.fromRGBO(96, 102, 214, 1),
      ));

  static ThemeData customDarkTheme = ThemeData(
      brightness: Brightness.dark,
      colorScheme: ColorScheme.dark(
        background: Colors.black,
        primary: Colors.white.withOpacity(0.87),
        onPrimary: Colors.white.withOpacity(0.60),
        secondary: Colors.grey[800]!,
        onSecondary: Colors.white.withOpacity(0.38),
        surface: const Color(0xff121212),
        onSurface: Colors.white.withOpacity(0.87),
        tertiary: Colors.white.withOpacity(0.80),
        onTertiary: const Color(0xff121212),
      ));
}

设置页面代码

Widget build(BuildContext context) {
  return Scaffold(
        appBar: AppBar(
            leading: IconButton(
              onPressed: () {
                Get.off(const HomePage());
              },
              icon: const Icon(
                Icons.arrow_back_outlined,
              ),
            ),
            iconTheme: const IconThemeData(color: Colors.white),
            title: Text(
              'Settings'.tr,
              style: TextStyle(
                  fontSize: 25.0,
                  fontWeight: FontWeight.bold,
                  color: Theme.of(context).colorScheme.primary),
            ),
            flexibleSpace: Container(
              decoration: Get.isDarkMode
                  ? const BoxDecoration(color: Color(0xff121212))
                  : const BoxDecoration(
                      gradient: LinearGradient(
                          begin: Alignment.topLeft,
                          end: Alignment.bottomRight,
                          colors: <Color>[
                            Color.fromRGBO(78, 84, 200, 1.0),
                            Color.fromRGBO(127, 133, 239, 1.0),
                          ]),
                    ),
            )),
        body: Container(
          padding: const EdgeInsets.all(8.0),
          child: ListView(
            children: [
              const SizedBox(
                height: 40.0,
              ),
              Row(
                children: [
                  Icon(
                    Icons.person,
                    color: Theme.of(context).colorScheme.onSurface,
                  ),
                  const SizedBox(
                    width: 10.0,
                  ),
                  Text('Account'.tr,
                      style: TextStyle(
                          color: Theme.of(context).colorScheme.tertiary,
                          fontSize: 20.0,
                          fontWeight: FontWeight.bold))
                ],
              ),
              const Divider(
                height: 20.0,
                thickness: 1.0,
              ),
              const SizedBox(
                height: 10.0,
              ),
              buildAccountOption(context, "Change Password".tr, 0),
              buildAccountOption(context, "Language".tr, 1),
              buildAccountOption(context, "Privacy and Security".tr, 2),
              buildAccountOption(context, "Delete Account".tr, 3),
              buildAccountOption(context, "Logout".tr, 4),
              const SizedBox(
                height: 40.0,
              ),
              Row(
                children: [
                  Icon(
                    Icons.theater_comedy,
                    color: Theme.of(context).colorScheme.onSurface,
                  ),
                  const SizedBox(
                    width: 10.0,
                  ),
                  Text('Theme',
                      style: TextStyle(
                          fontSize: 20.0,
                          fontWeight: FontWeight.bold,
                          color: Theme.of(context).colorScheme.tertiary))
                ],
              ),
              const Divider(
                height: 20.0,
                thickness: 1.0,
              ),
              const SizedBox(
                height: 10.0,
              ),
              buildNotificationOption2(
                "Theme Dark",
                valNotify1,
                onChangedFunc1,
              ),
/*               buildNotificationOption1(),
              const SizedBox(
                height: 10.0,
              ),
              Center(
                child: OutlinedButton(
                  style: OutlinedButton.styleFrom(
                      padding: const EdgeInsets.symmetric(horizontal: 40.0),
                      shape: RoundedRectangleBorder(
                        borderRadius: BorderRadius.circular(20.0),
                      )),
                  onPressed: () {},
                  child: const Text(
                    "Save",
                    style: TextStyle(
                        fontSize: 16.0,
                        color: Colors.black,
                        letterSpacing: 2.2),
                  ),
                ),
              ) */
            ],
          ),
        ),
      );
}

问题原因与解决方案

核心问题

GetMaterialApp配置逻辑冲突:同时设置theme和darkTheme,但theme直接根据控制器状态切换明暗主题,导致Flutter主题更新机制混乱,无法同步更新所有组件的主题上下文。

修复方案

  1. 规范主题配置
    保持theme为固定浅色主题,darkTheme为固定深色主题,通过themeMode控制当前主题模式。修改主页面代码:

    ThemeController themecontroller = Get.put(ThemeController());
    return GetMaterialApp(
        title: 'where to go',
        debugShowCheckedModeBanner: false,
        translations: Messages(),
        locale: mycontroller.initlang,
        theme: Themes.customLightTheme,
        darkTheme: Themes.customDarkTheme,
        themeMode: themecontroller.themedata ? ThemeMode.dark : ThemeMode.light,
        home: const SplashScreen());
    
  2. 确保主题状态可响应
    控制器中使用Rx变量存储主题状态,确保状态变化能触发UI更新:

    class ThemeController extends GetxController {
      RxBool isDarkMode = false.obs;
    
      void toggleTheme() {
        isDarkMode.value = !isDarkMode.value;
        // 可选:用GetStorage持久化状态
        // GetStorage().write('isDarkMode', isDarkMode.value);
      }
    
      @override
      void onInit() {
        super.onInit();
        // 可选:从本地恢复状态
        // isDarkMode.value = GetStorage().read('isDarkMode') ?? false;
      }
    }
    
  3. 更新设置页切换逻辑
    在设置页的切换回调中调用控制器的主题切换方法:

    void onChangedFunc1(bool value) {
      themecontroller.toggleTheme();
    }
    
  4. 移除硬编码颜色
    替换设置页中硬编码的颜色(如IconThemeData(color: Colors.white)),改用主题色:

    iconTheme: IconThemeData(color: Theme.of(context).colorScheme.onPrimary),
    

修改完成后,切换主题时所有组件颜色会即时同步更新,无需重启应用。


内容的提问来源于stack exchange,提问作者Emad Younan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 22:45:00