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

在自定义Flutter架构中实现darkTheme配置与主题切换

自定义Flutter架构下实现明暗主题切换方案

针对你基于AppConfig的自定义架构,无需依赖MaterialApp也能实现和原生一致的明暗主题切换,以下是分步实现方案:

1. 扩展AppConfig存储主题配置

首先修改AppConfig,添加亮色/暗色主题的静态配置项,支持自定义主题或使用默认值:

// config/app_config.dart
import 'package:flutter/material.dart';

class AppConfig {
  final String appName;
  final ThemeData lightTheme;
  final ThemeData darkTheme;

  AppConfig({
    required this.appName,
    ThemeData? lightTheme,
    ThemeData? darkTheme,
  })  : lightTheme = lightTheme ?? ThemeData.light(),
        darkTheme = darkTheme ?? ThemeData.dark();
}

2. 实现主题状态管理器

创建独立的主题状态管理类,用来动态控制当前主题模式(亮色/暗色/跟随系统),通过ChangeNotifier实现响应式更新:

// utils/theme_manager.dart
import 'package:flutter/material.dart';

class ThemeManager extends ChangeNotifier {
  ThemeMode _themeMode = ThemeMode.system;

  ThemeMode get themeMode => _themeMode;

  void setThemeMode(ThemeMode mode) {
    _themeMode = mode;
    notifyListeners(); // 通知组件主题变更
  }
}

3. 改造应用初始化流程

在initializeApp中注入AppConfig和ThemeManager,用Provider实现全局状态共享,替换原有的初始化逻辑:

// config/app_init.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../utils/theme_manager.dart';
import '../app_root.dart';
import 'app_config.dart';

Future<Widget> initializeApp(AppConfig config) async {
  // 保留你的其他初始化逻辑(如服务、数据库初始化)

  return MultiProvider(
    providers: [
      ChangeNotifierProvider(create: (_) => ThemeManager()),
      Provider.value(value: config),
    ],
    child: const AppRoot(),
  );
}

4. 构建根组件实现主题全局应用

创建AppRoot作为应用根组件,不用MaterialApp,直接用Theme组件全局注入主题,结合MediaQuery处理系统主题逻辑:

// app_root.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'config/app_config.dart';
import 'utils/theme_manager.dart';
import 'home_page.dart';

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

  @override
  Widget build(BuildContext context) {
    final appConfig = Provider.of<AppConfig>(context);
    final themeManager = Provider.of<ThemeManager>(context);

    // 根据当前主题模式返回对应ThemeData
    ThemeData _getCurrentTheme() {
      switch (themeManager.themeMode) {
        case ThemeMode.light:
          return appConfig.lightTheme;
        case ThemeMode.dark:
          return appConfig.darkTheme;
        case ThemeMode.system:
          final isSystemDark = MediaQuery.platformBrightnessOf(context) == Brightness.dark;
          return isSystemDark ? appConfig.darkTheme : appConfig.lightTheme;
      }
    }

    // 用Material组件提供Material风格组件的上下文环境
    return Theme(
      data: _getCurrentTheme(),
      child: Material(
        child: HomePage(appName: appConfig.appName),
      ),
    );
  }
}

5. 实现主题切换按钮

在页面中通过Provider获取ThemeManager,实现切换按钮逻辑:

// home_page.dart
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../utils/theme_manager.dart';

class HomePage extends StatelessWidget {
  final String appName;

  const HomePage({super.key, required this.appName});

  @override
  Widget build(BuildContext context) {
    final themeManager = Provider.of<ThemeManager>(context);
    final currentTheme = Theme.of(context);

    return Scaffold(
      appBar: AppBar(title: Text(appName)),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              '当前主题:${currentTheme.brightness == Brightness.light ? '亮色' : '暗色'}',
              style: currentTheme.textTheme.headlineSmall,
            ),
            const SizedBox(height: 20),
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                ElevatedButton(
                  onPressed: () => themeManager.setThemeMode(ThemeMode.light),
                  child: const Text('亮色模式'),
                ),
                const SizedBox(width: 10),
                ElevatedButton(
                  onPressed: () => themeManager.setThemeMode(ThemeMode.dark),
                  child: const Text('暗色模式'),
                ),
                const SizedBox(width: 10),
                ElevatedButton(
                  onPressed: () => themeManager.setThemeMode(ThemeMode.system),
                  child: const Text('跟随系统'),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

6. 主入口自定义主题初始化

在main.dart中可以自定义亮色/暗色主题,传入AppConfig:

// main.dart
import 'package:flutter/material.dart';
import 'config/app_config.dart';
import 'config/app_init.dart';
import 'restart_widget.dart';

Future<void> main() async {
  // 自定义主题示例
  final customLightTheme = ThemeData.light().copyWith(
    primaryColor: Colors.blue,
    appBarTheme: const AppBarTheme(color: Colors.blue),
  );

  final customDarkTheme = ThemeData.dark().copyWith(
    primaryColor: Colors.deepPurple,
    appBarTheme: const AppBarTheme(color: Colors.deepPurple),
  );

  AppConfig devAppConfig = AppConfig(
    appName: 'MedCare',
    lightTheme: customLightTheme,
    darkTheme: customDarkTheme,
  );
  Widget app = await initializeApp(devAppConfig);
  runApp(RestartWidget(child: app));
}

关键说明

  • 静态主题配置(亮色/暗色主题样式)存在AppConfig,动态主题模式(切换逻辑)由ThemeManager管理,职责分离
  • 用Flutter原生Theme组件替代MaterialApp的主题注入,实现全局主题应用
  • 通过Provider实现状态共享,主题切换时自动刷新所有依赖组件
  • 若使用Material风格组件,需用Material包裹根页面,提供必要的上下文环境

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 08:35:17