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

Flutter:修改应用主题时避免全局页面重建

主题切换导致全局重建并返回初始页面的解决方案

问题描述

使用Bloc和GoRouter进行Flutter开发时,切换主题(向ThemeBloc发送ToggleTheme事件)后,整个应用会全局重建并回到初始页面。尝试过用对话框、独立页面修改主题,问题依旧,希望实现无全局重建、不丢失导航栈的主题切换。

问题原因

当前AppView中用BlocBuilder包裹了整个MaterialApp.router,主题状态变化时会重建MaterialApp;同时每次重建都会调用AppRouter.mainRouter()创建新的GoRouter实例,导致导航栈丢失,回到初始路由。

解决方案

  1. 提前初始化GoRouter实例:避免每次重建MaterialApp时重新创建路由配置,保留导航栈状态。
  2. 仅更新themeMode属性:将BlocBuilder替换为context.watch,只更新MaterialApp的themeMode,不重建整个MaterialApp和GoRouter。

修改后的代码

App及AppView修改

final mainNavigatorKey = GlobalKey<NavigatorState>();
// 提前初始化GoRouter实例,复用同一个路由配置
final _appRouter = AppRouter.mainRouter(mainNavigatorKey);

class App extends StatelessWidget {
  const App({
    required this.themeRepository,
    required this.usersRepository,
    super.key,
  });

  final UsersRepository usersRepository;
  final ThemeRepository themeRepository;

  @override
  Widget build(BuildContext context) {
    return MultiRepositoryProvider(
      providers: [
        RepositoryProvider.value(value: usersRepository),
        RepositoryProvider.value(value: themeRepository),
      ],
      child: BlocProvider(
        create: (context) => ThemeBloc(themeRepository: themeRepository)
          ..add(ThemeModeRequested()),
        child: const AppView(),
      ),
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    // 监听ThemeBloc状态,仅获取themeMode
    final currentThemeMode = context.watch<ThemeBloc>().state.themeMode;
    
    return MaterialApp.router(
      theme: LighTheme.theme,
      darkTheme: DarkTheme.theme,
      themeMode: currentThemeMode, // 仅更新此属性
      localizationsDelegates: AppLocalizations.localizationsDelegates,
      supportedLocales: AppLocalizations.supportedLocales,
      routerConfig: _appRouter, // 使用预初始化的路由实例
    );
  }
}

确保ThemeBloc状态更新正确

class ThemeBloc extends Bloc<ThemeEvent, ThemeState> {
  final ThemeRepository themeRepository;

  ThemeBloc({required this.themeRepository}) : super(ThemeState.initial()) {
    on<ThemeModeRequested>(_onThemeModeRequested);
    on<ToggleThemeMode>(_onToggleThemeMode);
  }

  void _onThemeModeRequested(ThemeModeRequested event, Emitter<ThemeState> emit) async {
    final savedMode = await themeRepository.getThemeMode();
    emit(state.copyWith(themeMode: savedMode));
  }

  void _onToggleThemeMode(ToggleThemeMode event, Emitter<ThemeState> emit) async {
    await themeRepository.saveThemeMode(event.themeMode);
    emit(state.copyWith(themeMode: event.themeMode));
  }
}

说明

修改后,主题切换时只会更新MaterialApp的themeMode属性,不会重建整个MaterialApp和GoRouter实例,导航栈得以保留,实现无全局重建的主题切换效果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 06:43:12