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

Flutter自定义明暗主题用SharedPreferences存储后重启失效问题

问题根因

  1. 主题状态加载后未通知UI刷新
    ThemeColorData的loadTheme异步方法修改_isLight取值后,没有调用notifyListeners(),状态变更无法通知到UI层,导致重启后读取到的存储主题值不能生效。
  2. 异步加载时序问题
    loadTheme逻辑在build阶段触发,首次渲染时异步加载未完成,直接使用了默认的浅色主题值,且无后续刷新触发UI更新。
  3. BottomNavigationBar硬编码样式覆盖主题配置
    底部导航栏组件手动指定了unselectedItemColor: Colors.grey.shade500,覆盖了主题中bottomNavigationBarTheme的配置,导致主题色不生效。
  4. 异常页面布局配置错误
    手动给Container设置了和屏幕等高的高度,NestedScrollView的body可用高度小于屏幕高度,导致内容溢出、文本错位;额外设置的Container背景色也可能和主题Scaffold背景冲突。
    调试/模拟器环境下异步执行时序和真机release环境不同,加载逻辑可能刚好在首次渲染前完成,所以问题不会复现。

修复方案

1. 修复ThemeColorData状态通知逻辑

修改loadTheme方法,加载完成后通知UI刷新:

void loadTheme() async {
  await createSharedPrefObject();
  _isLight = _sharedPreferences!.getBool('themeData') ?? true;
  // 新增状态通知
  notifyListeners();
}

2. 优化主入口初始化逻辑

提前初始化SharedPreferences并传入Provider实例,用Consumer监听主题变化,保证状态更新能同步到MaterialApp:

Future<void> main() async {
  WidgetsFlutterBinding.ensureInitialized();
  // 提前初始化SharedPreferences避免重复实例化
  final sharedPref = await SharedPreferences.getInstance();
  runApp(
    ChangeNotifierProvider<ThemeColorData>(
      create: (context) => ThemeColorData()
        .._sharedPreferences = sharedPref
        ..loadTheme(),
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return Consumer<ThemeColorData>(
      builder: (context, themeProvider, child) {
        return MaterialApp(
          debugShowCheckedModeBanner: false,
          theme: themeProvider.themeColor,
          home: const SplashScreen(),
        );
      },
    );
  }
}

3. 移除底部导航栏硬编码样式

删除BottomNavigationBar中手动指定的颜色配置,优先使用主题配置:

bottomNavigationBar: BottomNavigationBar(
  items: [
    BottomNavigationBarItem(),
    BottomNavigationBarItem(),
    BottomNavigationBarItem()
  ],
  currentIndex: _selectedIndex,
  // 删除硬编码的unselectedItemColor配置
  onTap: _onItemTapped,
)

4. 修复异常页面布局

移除多余的背景色和高度设置,适配主题样式:

Widget build(BuildContext context) {
  return SafeArea(
    child: Scaffold(
      body: NestedScrollView(
        headerSliverBuilder: (BuildContext context, bool innerBoxIsScrolled) {
          return <Widget>[
            const SliverAppBar(),
          ];
        },
        // 直接用Padding作为body,移除多余的Container层
        body: Padding(
          padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5.0),
          child: SingleChildScrollView(
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                const SizedBox(height: 7),
                const Align(),
                const SizedBox(height: 10),
                SelectableText(
                  widget.dataModel.title,
                  style: Theme.of(context).textTheme.headline6!.copyWith(
                      fontFamily: 'Muli', fontWeight: FontWeight.w600),
                ),
                const SizedBox(height: 10),
                SelectableText(
                  widget.dataModel.longDescription,
                  style: TextStyle(
                      height: 1.3,
                      fontSize: 18,
                      fontFamily: 'Muli',
                      fontWeight: FontWeight.w300,
                      // 可选指定文本颜色适配当前主题
                      color: Theme.of(context).textTheme.bodyLarge?.color
                  ),
                ),
                const SizedBox(height: 10.0),
              ],
            ),
          ),
        ),
      ),
    ),
  );
}

内容的提问来源于stack exchange,提问作者Semih Yilmaz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 14:27:03