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

Flutter应用主题闪烁问题:热重启/启动时先暗后亮求助

Flutter 主题闪烁问题解决方案

问题根源

你的主题闪烁是因为ThemeModeCubit初始化时默认状态为ThemeMode.dark,而从SharedPreferences加载主题偏好的操作是异步的。应用启动或热重启时,会先以深色主题渲染UI,等异步加载完成后才切换到保存的浅色主题,从而出现短暂闪烁。

解决方案

方案1:提前初始化主题偏好,设置Cubit正确初始状态

在main函数中先完成SharedPreferences的初始化和主题偏好读取,再将正确的主题状态作为初始值传入Cubit,避免初始渲染错误主题。

修改后的main.dart

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:notes_revision/cubits/theme_mode_cubit.dart/theme_mode_cubit.dart';
import 'package:notes_revision/views/home_view.dart';
import 'package:shared_preferences/shared_preferences.dart';

void main() async {
  // 确保Flutter框架绑定初始化完成
  WidgetsFlutterBinding.ensureInitialized();
  // 提前读取主题偏好
  SharedPreferences prefs = await SharedPreferences.getInstance();
  bool isDark = prefs.getBool('isDark') ?? false;
  ThemeMode initialTheme = isDark ? ThemeMode.dark : ThemeMode.light;

  runApp(MyApp(initialTheme: initialTheme));
}

class MyApp extends StatelessWidget {
  final ThemeMode initialTheme;
  const MyApp({super.key, required this.initialTheme});

  @override
  Widget build(BuildContext context) {
    return BlocProvider(
      create: (context) => ThemeModeCubit(initialTheme),
      child: Builder(builder: (context) {
        return BlocBuilder<ThemeModeCubit, ThemeMode>(
          builder: (context, state) {
            return MaterialApp(
              title: 'Notes App',
              darkTheme: ThemeData.dark(),
              theme: ThemeData.light(), // 显式设置浅色主题,保证一致性
              themeMode: state,
              debugShowCheckedModeBanner: false,
              home: const HomeView(),
            );
          },
        );
      }),
    );
  }
}

修改后的ThemeModeCubit.dart

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:shared_preferences/shared_preferences.dart';

class ThemeModeCubit extends Cubit<ThemeMode> {
  // 接收外部传入的初始主题状态
  ThemeModeCubit(ThemeMode initialTheme) : super(initialTheme);

  void toggleModes() async {
    SharedPreferences sharedPreferences = await SharedPreferences.getInstance();
    if (state == ThemeMode.dark) {
      emit(ThemeMode.light);
      sharedPreferences.setBool('isDark', false);
    } else {
      emit(ThemeMode.dark);
      sharedPreferences.setBool('isDark', true);
    }
  }
}

方案2:用FutureBuilder等待主题加载完成

如果不想修改main函数的初始化流程,可以在MaterialApp外层使用FutureBuilder,等待主题偏好加载完成后再渲染UI,同时可添加加载占位提升体验。

修改后的MyApp组件

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

  Future<ThemeMode> _getInitialTheme() async {
    SharedPreferences prefs = await SharedPreferences.getInstance();
    bool isDark = prefs.getBool('isDark') ?? false;
    return isDark ? ThemeMode.dark : ThemeMode.light;
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<ThemeMode>(
      future: _getInitialTheme(),
      builder: (context, snapshot) {
        // 加载中显示占位组件,避免空白或错误主题闪烁
        if (!snapshot.hasData) {
          return const MaterialApp(
            home: Scaffold(
              body: Center(child: CircularProgressIndicator()),
            ),
          );
        }
        return BlocProvider(
          create: (context) => ThemeModeCubit(snapshot.data!),
          child: BlocBuilder<ThemeModeCubit, ThemeMode>(
            builder: (context, state) {
              return MaterialApp(
                title: 'Notes App',
                darkTheme: ThemeData.dark(),
                theme: ThemeData.light(),
                themeMode: state,
                debugShowCheckedModeBanner: false,
                home: const HomeView(),
              );
            },
          ),
        );
      },
    );
  }
}

额外优化建议

  • 始终显式设置theme和darkTheme,避免依赖系统默认主题,保证主题切换的一致性。
  • 可以添加自定义启动页(Splash Screen),替换加载时的进度指示器,进一步提升用户体验。

内容的提问来源于stack exchange,提问作者Omar Elhbrouk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 00:53:17