阅读视图

发现新文章,点击刷新页面。

《Flutter全栈开发实战指南:从零到高级》- 20 -主题与国际化

引言

在移动应用开发中,用户体验个性化已成为基本要求,这里将深入探讨Flutter应用中的主题切换和国际化实现。掌握这些技能,让你的应用能够适应不同用户群体的视觉偏好和语言需求。 在这里插入图片描述

为什么需要主题与国际化?

Flutter提供了强大的主题和国际化支持,但很多开发者在实际项目中会遇到以下问题:

  • 如何实现丝滑的主题切换?
  • 如何管理动态主题配置?
  • 如何处理多语言资源?以及如何实现运行时语言切换?

本文将带着以上疑惑一一解答这些问题

一、主题系统

1.1 架构原理

Flutter的主题系统基于继承(Inheritance) 设计模式构建。让我们通过一个架构图来加深理解:

graph TB
    A[MaterialApp] --> B[ThemeData]
    B --> C[ColorScheme]
    B --> D[TextTheme]
    B --> E[Other Themes]
    C --> F[primaryColor]
    C --> G[secondaryColor]
    C --> H[surfaceColor]
    D --> I[headline1]
    D --> J[bodyText1]
    D --> K[caption]
    
    style1[Widget] -.-> B
    style2[Widget] -.-> B
    style3[Widget] -.-> B
    
    subgraph "Theme Scope"
        B
    end

核心原理ThemeData对象通过Theme widget在整个widget树中向下传递,任何子widget都可以通过Theme.of(context)获取当前主题数据。

1.2 主题配置

亮色主题
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '主题与国际化',
      // 默认亮色主题
      theme: ThemeData(
        // 使用ColorScheme定义颜色
        colorScheme: ColorScheme.fromSeed(
          seedColor: Colors.blue, 
          brightness: Brightness.light, 
        ),
        // 主题配置
        textTheme: const TextTheme(
          displayLarge: TextStyle(
            fontSize: 32,
            fontWeight: FontWeight.bold,
            color: Colors.black87,
          ),
          bodyLarge: TextStyle(
            fontSize: 16,
            color: Colors.black87,
          ),
        ),
        // 组件主题配置
        elevatedButtonTheme: ElevatedButtonThemeData(
          style: ElevatedButton.styleFrom(
            padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
            shape: RoundedRectangleBorder(
              borderRadius: BorderRadius.circular(8),
            ),
          ),
        ),
        // 应用栏主题
        appBarTheme: const AppBarTheme(
          centerTitle: true,
          elevation: 2,
        ),
      ),
      home: const HomePage(),
    );
  }
}
暗色主题
// 暗色主题配置
ThemeData darkTheme = ThemeData(
  colorScheme: ColorScheme.fromSeed(
    seedColor: Colors.blue,
    brightness: Brightness.dark, 
  ),
  // 暗色模式下的文本颜色需要调整
  textTheme: const TextTheme(
    displayLarge: TextStyle(
      fontSize: 32,
      fontWeight: FontWeight.bold,
      color: Colors.white70, 
    ),
    bodyLarge: TextStyle(
      fontSize: 16,
      color: Colors.white70,
    ),
  ),
  scaffoldBackgroundColor: Colors.grey[900], 
);

1.3 使用主题

在Widget中使用主题
class ThemedWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 获取当前主题
    final theme = Theme.of(context);
    final colorScheme = theme.colorScheme;
    final textTheme = theme.textTheme;
    
    return Container(
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: colorScheme.primaryContainer, // 使用主题颜色
        borderRadius: BorderRadius.circular(12),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            '标题文本',
            style: textTheme.headlineMedium?.copyWith(
              color: colorScheme.onPrimaryContainer,
            ),
          ),
          const SizedBox(height: 8),
          Text(
            '老师的会计法律束带结发拉卡萨电极法啦束带结发。',
            style: textTheme.bodyLarge?.copyWith(
              color: colorScheme.onPrimaryContainer.withOpacity(0.8),
            ),
          ),
          const SizedBox(height: 16),
          // 使用主题化的按钮
          ElevatedButton(
            onPressed: () {},
            child: Text('主题按钮'),
          ),
        ],
      ),
    );
  }
}
自定义主题扩展

有时我们需要在主题中添加自定义属性,可以通过扩展ThemeExtension来实现:

// 1. 创建主题扩展类
@immutable
class CustomColors extends ThemeExtension<CustomColors> {
  const CustomColors({
    required this.success,
    required this.warning,
    required this.danger,
    required this.info,
  });

  final Color success;
  final Color warning;
  final Color danger;
  final Color info;

  @override
  ThemeExtension<CustomColors> copyWith({
    Color? success,
    Color? warning,
    Color? danger,
    Color? info,
  }) {
    return CustomColors(
      success: success ?? this.success,
      warning: warning ?? this.warning,
      danger: danger ?? this.danger,
      info: info ?? this.info,
    );
  }

  @override
  ThemeExtension<CustomColors> lerp(
    ThemeExtension<CustomColors>? other, 
    double t,
  ) {
    if (other is! CustomColors) {
      return this;
    }
    return CustomColors(
      success: Color.lerp(success, other.success, t)!,
      warning: Color.lerp(warning, other.warning, t)!,
      danger: Color.lerp(danger, other.danger, t)!,
      info: Color.lerp(info, other.info, t)!,
    );
  }
}

// 2. 在主题中使用
ThemeData(
  extensions: const <ThemeExtension<dynamic>>[
    CustomColors(
      success: Colors.green,
      warning: Colors.orange,
      danger: Colors.red,
      info: Colors.blue,
    ),
  ],
);

// 3. 在Widget中使用
final customColors = Theme.of(context).extension<CustomColors>()!;
Container(
  color: customColors.success,
  child: Text('成功状态', style: TextStyle(color: Colors.white)),
);

二、动态主题切换

2.1 状态管理方案选择

对于主题切换,我们需要一个全局状态管理方案。以下是几种常见方案的对比:

方案 优点 缺点 适用场景
Provider 官方推荐 需要一定学习成本 中小型应用
Riverpod 类型安全,编译时检查 概念较多,有一定学习成本 中大型应用
Bloc 状态管理规范 模板代码多 大型复杂应用
GetX 简单快捷 耦合度较高 快速开发

这里我们使用Provider,因为它是Flutter官方推荐且学习起来相对简单。

2.2 主题管理实现

步骤1:创建主题状态管理类
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

// 主题模式枚举
enum ThemeModeType {
  light,    // 亮色模式
  dark,     // 暗色模式
  system,   // 跟随系统
  custom,   // 自定义
}

// 主题管理器
class ThemeManager with ChangeNotifier {
  ThemeModeType _themeMode = ThemeModeType.system;
  ThemeData _lightTheme = _defaultLightTheme;
  ThemeData _darkTheme = _defaultDarkTheme;
  ThemeData? _customTheme;
  
  // 亮色主题
  static final ThemeData _defaultLightTheme = ThemeData(
    colorScheme: ColorScheme.fromSeed(
      seedColor: Colors.blue,
      brightness: Brightness.light,
    ),
    useMaterial3: true,
  );
  
  // 暗色主题
  static final ThemeData _defaultDarkTheme = ThemeData(
    colorScheme: ColorScheme.fromSeed(
      seedColor: Colors.blue,
      brightness: Brightness.dark,
    ),
    useMaterial3: true,
  );
  
  // 获取当前主题模式
  ThemeModeType get themeMode => _themeMode;
  
  // 获取当前主题数据
  ThemeData get currentTheme {
    switch (_themeMode) {
      case ThemeModeType.light:
        return _lightTheme;
      case ThemeModeType.dark:
        return _darkTheme;
      case ThemeModeType.custom:
        return _customTheme ?? _defaultLightTheme;
      case ThemeModeType.system:
      default:
        // 根据系统设置决定
        final platformBrightness = WidgetsBinding.instance.window.platformBrightness;
        return platformBrightness == Brightness.dark ? _darkTheme : _lightTheme;
    }
  }
  
  // 切换主题
  Future<void> switchTheme(ThemeModeType newMode) async {
    _themeMode = newMode;
    
    // 保存到本地存储
    final prefs = await SharedPreferences.getInstance();
    await prefs.setInt('theme_mode', newMode.index);
    
    // 通知监听者
    notifyListeners();
  }
  
  // 自定义主题
  Future<void> setCustomTheme(ThemeData theme) async {
    _customTheme = theme;
    _themeMode = ThemeModeType.custom;
    
    // 保存配置
    final prefs = await SharedPreferences.getInstance();
    await prefs.setInt('theme_mode', ThemeModeType.custom.index);
    
    notifyListeners();
  }
  
  // 缓存中获取主题设置
  Future<void> loadThemeFromPrefs() async {
    final prefs = await SharedPreferences.getInstance();
    final savedModeIndex = prefs.getInt('theme_mode');
    
    if (savedModeIndex != null) {
      final savedMode = ThemeModeType.values[savedModeIndex];
      _themeMode = savedMode;
      notifyListeners();
    }
  }
  
  // 更新亮色
  void updateLightTheme(ThemeData newTheme) {
    _lightTheme = newTheme;
    if (_themeMode == ThemeModeType.light) {
      notifyListeners();
    }
  }
  
  // 更新暗色
  void updateDarkTheme(ThemeData newTheme) {
    _darkTheme = newTheme;
    if (_themeMode == ThemeModeType.dark) {
      notifyListeners();
    }
  }
}
步骤2:在应用入口配置Provider
void main() async {
  // 确保WidgetsFlutterBinding初始化
  WidgetsFlutterBinding.ensureInitialized();
  
  // 创建主题实例
  final themeManager = ThemeManager();
  
  // 加载保存的主题设置
  await themeManager.loadThemeFromPrefs();
  
  runApp(
    // 使用MultiProvider包装应用
    MultiProvider(
      providers: [
        ChangeNotifierProvider.value(value: themeManager),
        // 其他Provider...
      ],
      child: const MyApp(),
    ),
  );
}

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

  @override
  Widget build(BuildContext context) {
    // 使用Consumer监听主题变化
    return Consumer<ThemeManager>(
      builder: (context, themeManager, child) {
        return MaterialApp(
          title: '主题与国际化',
          // 使用主题管理器中的当前主题
          theme: themeManager.currentTheme,
          darkTheme: themeManager.currentTheme, 
          themeMode: ThemeMode.system, 
          home: const HomePage(),
        );
      },
    );
  }
}
步骤3:创建主题切换界面
class ThemeSettingsPage extends StatelessWidget {
  const ThemeSettingsPage({super.key});

  @override
  Widget build(BuildContext context) {
    final themeManager = Provider.of<ThemeManager>(context);
    
    return Scaffold(
      appBar: AppBar(
        title: const Text('主题设置'),
      ),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          // 主题模式选择卡片
          _buildThemeModeCard(themeManager),
          const SizedBox(height: 24),
          
          // 亮色主题
          _buildThemeCustomizationCard(
            themeManager,
            isDark: false,
          ),
          const SizedBox(height: 24),
          
          // 暗色主题
          _buildThemeCustomizationCard(
            themeManager,
            isDark: true,
          ),
          const SizedBox(height: 24),
          
          // 主题预览
          _buildThemePreviewCard(context),
        ],
      ),
    );
  }
  
  Widget _buildThemeModeCard(ThemeManager themeManager) {
    return Card(
      elevation: 2,
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text(
              '主题模式',
              style: TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 12),
            // 主题模式选项
            ...ThemeModeType.values.map((mode) {
              return RadioListTile<ThemeModeType>(
                title: Text(_getThemeModeName(mode)),
                value: mode,
                groupValue: themeManager.themeMode,
                onChanged: (value) {
                  if (value != null) {
                    themeManager.switchTheme(value);
                  }
                },
              );
            }).toList(),
          ],
        ),
      ),
    );
  }
  
  String _getThemeModeName(ThemeModeType mode) {
    switch (mode) {
      case ThemeModeType.light:
        return '亮色模式';
      case ThemeModeType.dark:
        return '暗色模式';
      case ThemeModeType.system:
        return '跟随系统';
      case ThemeModeType.custom:
        return '自定义主题';
    }
  }
  
  Widget _buildThemeCustomizationCard(
    ThemeManager themeManager, {
    required bool isDark,
  }) {
    return Card(
      elevation: 2,
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              isDark ? '暗色主题' : '亮色主题',
              style: const TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 12),
            
            // 主题色选择
            const Text('主题色'),
            const SizedBox(height: 8),
            
            // 颜色选择器
            Wrap(
              spacing: 8,
              runSpacing: 8,
              children: [
                _buildColorOption(
                  color: Colors.blue,
                  isSelected: true,
                  onTap: () => _updateThemeColor(themeManager, Colors.blue, isDark),
                ),
                _buildColorOption(
                  color: Colors.green,
                  isSelected: false,
                  onTap: () => _updateThemeColor(themeManager, Colors.green, isDark),
                ),
                _buildColorOption(
                  color: Colors.red,
                  isSelected: false,
                  onTap: () => _updateThemeColor(themeManager, Colors.red, isDark),
                ),
                _buildColorOption(
                  color: Colors.purple,
                  isSelected: false,
                  onTap: () => _updateThemeColor(themeManager, Colors.purple, isDark),
                ),
                _buildColorOption(
                  color: Colors.orange,
                  isSelected: false,
                  onTap: () => _updateThemeColor(themeManager, Colors.orange, isDark),
                ),
                _buildColorOption(
                  color: Colors.teal,
                  isSelected: false,
                  onTap: () => _updateThemeColor(themeManager, Colors.teal, isDark),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
  
  Widget _buildColorOption({
    required Color color,
    required bool isSelected,
    required VoidCallback onTap,
  }) {
    return GestureDetector(
      onTap: onTap,
      child: Container(
        width: 40,
        height: 40,
        decoration: BoxDecoration(
          color: color,
          shape: BoxShape.circle,
          border: isSelected
              ? Border.all(color: Colors.white, width: 3)
              : null,
          boxShadow: [
            BoxShadow(
              color: Colors.black.withOpacity(0.1),
              blurRadius: 4,
              offset: const Offset(0, 2),
            ),
          ],
        ),
        child: isSelected
            ? const Icon(Icons.check, color: Colors.white, size: 20)
            : null,
      ),
    );
  }
  
  void _updateThemeColor(
    ThemeManager themeManager, 
    Color color, 
    bool isDark,
  ) {
    final newTheme = ThemeData(
      colorScheme: ColorScheme.fromSeed(
        seedColor: color,
        brightness: isDark ? Brightness.dark : Brightness.light,
      ),
      useMaterial3: true,
    );
    
    if (isDark) {
      themeManager.updateDarkTheme(newTheme);
    } else {
      themeManager.updateLightTheme(newTheme);
    }
  }
  
  Widget _buildThemePreviewCard(BuildContext context) {
    final theme = Theme.of(context);
    
    return Card(
      elevation: 2,
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Text(
              '主题预览',
              style: TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 12),
            
            // 组件预览
            Column(
              children: [
                // 按钮
                Wrap(
                  spacing: 8,
                  children: [
                    ElevatedButton(
                      onPressed: () {},
                      child: const Text('主要按钮'),
                    ),
                    OutlinedButton(
                      onPressed: () {},
                      child: const Text('轮廓按钮'),
                    ),
                    TextButton(
                      onPressed: () {},
                      child: const Text('文本按钮'),
                    ),
                  ],
                ),
                const SizedBox(height: 16),
                
                // 卡片预览
                Card(
                  child: Padding(
                    padding: const EdgeInsets.all(12),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          '卡片标题',
                          style: theme.textTheme.titleLarge,
                        ),
                        const SizedBox(height: 8),
                        Text(
                          '这是一个卡片内容的预览,这是一个卡片内容的预览,这是一个卡片内容的预览。',
                          style: theme.textTheme.bodyMedium,
                        ),
                      ],
                    ),
                  ),
                ),
                const SizedBox(height: 16),
                
                // 颜色预览
                Row(
                  children: [
                    _buildColorPreview('主色', theme.colorScheme.primary),
                    const SizedBox(width: 8),
                    _buildColorPreview('辅色', theme.colorScheme.secondary),
                    const SizedBox(width: 8),
                    _buildColorPreview('背景', theme.colorScheme.background),
                  ],
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
  
  Widget _buildColorPreview(String label, Color color) {
    return Expanded(
      child: Column(
        children: [
          Container(
            height: 40,
            decoration: BoxDecoration(
              color: color,
              borderRadius: BorderRadius.circular(8),
              border: Border.all(color: Colors.grey.shade300),
            ),
          ),
          const SizedBox(height: 4),
          Text(
            label,
            style: const TextStyle(fontSize: 12),
          ),
        ],
      ),
    );
  }
}

2.3 渐变主题与动画切换

// 渐变主题切换
class AnimatedThemeSwitcher extends StatefulWidget {
  final Widget child;
  
  const AnimatedThemeSwitcher({super.key, required this.child});
  
  @override
  State<AnimatedThemeSwitcher> createState() => _AnimatedThemeSwitcherState();
}

class _AnimatedThemeSwitcherState extends State<AnimatedThemeSwitcher> 
    with SingleTickerProviderStateMixin {
  
  late AnimationController _controller;
  late Animation<double> _animation;
  
  @override
  void initState() {
    super.initState();
    
    // 创建动画控制器
    _controller = AnimationController(
      duration: const Duration(milliseconds: 300),
      vsync: this,
    );
    
    // 创建缓动动画
    _animation = CurvedAnimation(
      parent: _controller,
      curve: Curves.easeInOut,
    );
  }
  
  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    
    // 监听主题变化,开始动画
    final themeManager = Provider.of<ThemeManager>(context, listen: true);
    
    // 每次主题变化时重新启动动画
    _controller.forward(from: 0);
  }
  
  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _animation,
      builder: (context, child) {
        return Opacity(
          opacity: _animation.value,
          child: Transform.scale(
            scale: 0.95 + 0.05 * _animation.value,
            child: child,
          ),
        );
      },
      child: widget.child,
    );
  }
  
  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }
}

三、国际化

3.1 Flutter国际化架构

Flutter国际化系统基于Localizations机制,其工作流程如下:

sequenceDiagram
    participant App as 应用程序
    participant MaterialApp as MaterialApp
    participant Localizations as Localizations
    participant Delegate as 本地化代理
    participant Resource as 资源文件
    participant Widget as Widget
    
    App->>MaterialApp: 提供localizationsDelegates
    MaterialApp->>Localizations: 加载本地化配置
    Localizations->>Delegate: 请求本地化资源
    Delegate->>Resource: 加载对应语言资源
    Resource-->>Delegate: 返回资源数据
    Delegate-->>Localizations: 返回Localizations类
    Localizations-->>MaterialApp: 建立本地化上下文
    Widget->>Localizations: 通过Localizations.of获取文本
    Localizations-->>Widget: 返回本地化文本

3.2 国际化配置

步骤1:添加依赖
# pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  intl: ^0.18.1 # 用于日期、数字格式化
  shared_preferences: ^2.2.2 
步骤2:创建国际化支持类
// lib/l10n/app_localizations.dart
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

// 代理
class AppLocalizationsDelegate extends LocalizationsDelegate<AppLocalizations> {
  const AppLocalizationsDelegate();

  @override
  bool isSupported(Locale locale) {
    // 支持的语言列表
    return ['en', 'zh', 'ja', 'ko'].contains(locale.languageCode);
  }

  @override
  Future<AppLocalizations> load(Locale locale) {
    // 加载对应的本地化资源
    return SynchronousFuture<AppLocalizations>(AppLocalizations(locale));
  }

  @override
  bool shouldReload(AppLocalizationsDelegate old) => false;
}

// 本地化类
class AppLocalizations {
  final Locale locale;

  AppLocalizations(this.locale);

  // 静态方法
  static AppLocalizations? of(BuildContext context) {
    return Localizations.of<AppLocalizations>(context, AppLocalizations);
  }

  // 资源文件映射
  static final Map<String, Map<String, String>> _localizedValues = {
    'en': {
      'appTitle': 'Flutter Internationalization Demo',
      'welcome': 'Welcome to Flutter!',
      'login': 'Login',
      'logout': 'Logout',
      'settings': 'Settings',
      'language': 'Language',
      'theme': 'Theme',
      'darkMode': 'Dark Mode',
      'lightMode': 'Light Mode',
      'systemMode': 'System Mode',
      'changeLanguage': 'Change Language',
      'currentLanguage': 'Current Language',
      'english': 'English',
      'chinese': 'Chinese',
      'japanese': 'Japanese',
      'korean': 'Korean',
      'home': 'Home',
      'profile': 'Profile',
      'messages': 'Messages',
      'notifications': 'Notifications',
      'search': 'Search',
      'submit': 'Submit',
      'cancel': 'Cancel',
      'save': 'Save',
      'delete': 'Delete',
      'edit': 'Edit',
      'view': 'View',
      'loading': 'Loading...',
      'error': 'An error occurred',
      'success': 'Operation successful',
      'warning': 'Warning',
      'info': 'Information',
      'confirm': 'Confirm',
      'back': 'Back',
      'next': 'Next',
      'previous': 'Previous',
      'close': 'Close',
      'open': 'Open',
      'yes': 'Yes',
      'no': 'No',
      'ok': 'OK',
      'retry': 'Retry',
      'skip': 'Skip',
      'continue': 'Continue',
      'finished': 'Finished',
      'start': 'Start',
      'stop': 'Stop',
      'pause': 'Pause',
      'resume': 'Resume',
    },
    'zh': {
      'appTitle': 'Flutter国际化示例',
      'welcome': '欢迎使用Flutter!',
      'login': '登录',
      'logout': '退出登录',
      'settings': '设置',
      'language': '语言',
      'theme': '主题',
      'darkMode': '暗色模式',
      'lightMode': '亮色模式',
      'systemMode': '系统模式',
      'changeLanguage': '切换语言',
      'currentLanguage': '当前语言',
      'english': '英语',
      'chinese': '中文',
      'japanese': '日语',
      'korean': '韩语',
      'home': '首页',
      'profile': '个人资料',
      'messages': '消息',
      'notifications': '通知',
      'search': '搜索',
      'submit': '提交',
      'cancel': '取消',
      'save': '保存',
      'delete': '删除',
      'edit': '编辑',
      'view': '查看',
      'loading': '加载中...',
      'error': '发生错误',
      'success': '操作成功',
      'warning': '警告',
      'info': '信息',
      'confirm': '确认',
      'back': '返回',
      'next': '下一步',
      'previous': '上一步',
      'close': '关闭',
      'open': '打开',
      'yes': '是',
      'no': '否',
      'ok': '确定',
      'retry': '重试',
      'skip': '跳过',
      'continue': '继续',
      'finished': '完成',
      'start': '开始',
      'stop': '停止',
      'pause': '暂停',
      'resume': '恢复',
    },
    'ja': {
      'appTitle': 'Flutter国際化デモ',
      'welcome': 'Flutterへようこそ!',
      'login': 'ログイン',
      'logout': 'ログアウト',
      'settings': '設定',
      'language': '言語',
      'theme': 'テーマ',
      'darkMode': 'ダークモード',
      'lightMode': 'ライトモード',
      'systemMode': 'システムモード',
      'changeLanguage': '言語を切り替える',
      'currentLanguage': '現在の言語',
      'english': '英語',
      'chinese': '中国語',
      'japanese': '日本語',
      'korean': '韓国語',
      'home': 'ホーム',
      'profile': 'プロフィール',
      'messages': 'メッセージ',
      'notifications': '通知',
      'search': '検索',
      'submit': '送信',
      'cancel': 'キャンセル',
      'save': '保存',
      'delete': '削除',
      'edit': '編集',
      'view': '表示',
      'loading': '読み込み中...',
      'error': 'エラーが発生しました',
      'success': '操作が成功しました',
      'warning': '警告',
      'info': '情報',
      'confirm': '確認',
      'back': '戻る',
      'next': '次へ',
      'previous': '前へ',
      'close': '閉じる',
      'open': '開く',
      'yes': 'はい',
      'no': 'いいえ',
      'ok': 'OK',
      'retry': '再試行',
      'skip': 'スキップ',
      'continue': '続行',
      'finished': '完了',
      'start': '開始',
      'stop': '停止',
      'pause': '一時停止',
      'resume': '再開',
    },
    'ko': {
      'appTitle': 'Flutter 국제화 데모',
      'welcome': 'Flutter에 오신 것을 환영합니다!',
      'login': '로그인',
      'logout': '로그아웃',
      'settings': '설정',
      'language': '언어',
      'theme': '테마',
      'darkMode': '다크 모드',
      'lightMode': '라이트 모드',
      'systemMode': '시스템 모드',
      'changeLanguage': '언어 변경',
      'currentLanguage': '현재 언어',
      'english': '영어',
      'chinese': '중국어',
      'japanese': '일본어',
      'korean': '한국어',
      'home': '홈',
      'profile': '프로필',
      'messages': '메시지',
      'notifications': '알림',
      'search': '검색',
      'submit': '제출',
      'cancel': '취소',
      'save': '저장',
      'delete': '삭제',
      'edit': '편집',
      'view': '보기',
      'loading': '로딩 중...',
      'error': '오류가 발생했습니다',
      'success': '작업이 성공했습니다',
      'warning': '경고',
      'info': '정보',
      'confirm': '확인',
      'back': '뒤로',
      'next': '다음',
      'previous': '이전',
      'close': '닫기',
      'open': '열기',
      'yes': '예',
      'no': '아니오',
      'ok': '확인',
      'retry': '재시도',
      'skip': '건너뛰기',
      'continue': '계속',
      'finished': '완료',
      'start': '시작',
      'stop': '중지',
      'pause': '일시 정지',
      'resume': '재개',
    },
  };

  // 获取本地化文本
  String? _getText(String key) {
    if (_localizedValues.containsKey(locale.toString())) {
      return _localizedValues[locale.toString()]![key];
    }
    
    if (_localizedValues.containsKey(locale.languageCode)) {
      return _localizedValues[locale.languageCode]![key];
    }
    
    // 兜底
    return _localizedValues['en']![key];
  }

  // getter方法
  String get appTitle => _getText('appTitle')!;
  String get welcome => _getText('welcome')!;
  String get login => _getText('login')!;
  String get logout => _getText('logout')!;
  String get settings => _getText('settings')!;
  String get language => _getText('language')!;
  String get theme => _getText('theme')!;
  String get darkMode => _getText('darkMode')!;
  String get lightMode => _getText('lightMode')!;
  String get systemMode => _getText('systemMode')!;
  String get changeLanguage => _getText('changeLanguage')!;
  String get currentLanguage => _getText('currentLanguage')!;
  String get english => _getText('english')!;
  String get chinese => _getText('chinese')!;
  String get japanese => _getText('japanese')!;
  String get korean => _getText('korean')!;
  String get home => _getText('home')!;
  String get profile => _getText('profile')!;
  String get messages => _getText('messages')!;
  String get notifications => _getText('notifications')!;
  String get search => _getText('search')!;
  String get submit => _getText('submit')!;
  String get cancel => _getText('cancel')!;
  String get save => _getText('save')!;
  String get delete => _getText('delete')!;
  String get edit => _getText('edit')!;
  String get view => _getText('view')!;
  String get loading => _getText('loading')!;
  String get error => _getText('error')!;
  String get success => _getText('success')!;
  String get warning => _getText('warning')!;
  String get info => _getText('info')!;
  String get confirm => _getText('confirm')!;
  String get back => _getText('back')!;
  String get next => _getText('next')!;
  String get previous => _getText('previous')!;
  String get close => _getText('close')!;
  String get open => _getText('open')!;
  String get yes => _getText('yes')!;
  String get no => _getText('no')!;
  String get ok => _getText('ok')!;
  String get retry => _getText('retry')!;
  String get skip => _getText('skip')!;
  String get continueText => _getText('continue')!;
  String get finished => _getText('finished')!;
  String get start => _getText('start')!;
  String get stop => _getText('stop')!;
  String get pause => _getText('pause')!;
  String get resume => _getText('resume')!;

  // 携带参数
  String welcomeUser(String username) {
    // 根据不同语言调整格式
    switch (locale.languageCode) {
      case 'zh':
        return '欢迎, $username!';
      case 'ja':
        return 'ようこそ、$usernameさん!';
      case 'ko':
        return '환영합니다, $username님!';
      default:
        return 'Welcome, $username!';
    }
  }

  // 数字格式化
  String formatNumber(int number) {
    final formatter = NumberFormat.decimalPattern(locale.toString());
    return formatter.format(number);
  }

  // 货币格式化
  String formatCurrency(double amount) {
    final formatter = NumberFormat.currency(
      locale: locale.toString(),
      symbol: _getCurrencySymbol(locale.languageCode),
    );
    return formatter.format(amount);
  }

  String _getCurrencySymbol(String languageCode) {
    switch (languageCode) {
      case 'zh':
        return '¥';
      case 'ja':
        return '¥';
      case 'ko':
        return '₩';
      default:
        return '\$';
    }
  }

  // 日期格式化
  String formatDate(DateTime date) {
    final formatter = DateFormat.yMMMMd(locale.toString());
    return formatter.format(date);
  }

  // 时间格式化
  String formatRelativeTime(DateTime date) {
    final now = DateTime.now();
    final difference = now.difference(date);
    
    if (difference.inDays > 0) {
      return _pluralize(difference.inDays, 'day', 'days');
    } else if (difference.inHours > 0) {
      return _pluralize(difference.inHours, 'hour', 'hours');
    } else if (difference.inMinutes > 0) {
      return _pluralize(difference.inMinutes, 'minute', 'minutes');
    } else {
      return _getText('justNow') ?? 'Just now';
    }
  }

  String _pluralize(int count, String singular, String plural) {
    // 简单处理
    if (count == 1) {
      return '$count $singular';
    } else {
      return '$count $plural';
    }
  }
}
步骤3:配置MaterialApp
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '国际化',
      // 支持的语言列表
      supportedLocales: const [
        Locale('en', 'US'), // 英文
        Locale('zh', 'CN'), // 中文
        Locale('ja', 'JP'), // 日文
        Locale('ko', 'KR'), // 韩文
      ],
      // 本地化代理
      localizationsDelegates: const [
        AppLocalizationsDelegate(), // 自定义代理
        GlobalMaterialLocalizations.delegate,  // Material组件本地化
        GlobalWidgetsLocalizations.delegate,   // Widget文本本地化
        GlobalCupertinoLocalizations.delegate, // iOS风格组件本地化
      ],
      // 找不到对应语言时的回退语言
      localeResolutionCallback: (locale, supportedLocales) {
        // 检查支持的语言
        for (var supportedLocale in supportedLocales) {
          if (supportedLocale.languageCode == locale?.languageCode) {
            return supportedLocale;
          }
        }
        // 默认英语
        return const Locale('en', 'US');
      },
      home: const HomePage(),
    );
  }
}

3.3 语言管理器

// lib/providers/language_manager.dart
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';

// 语言管理器
class LanguageManager with ChangeNotifier {
  Locale _locale = const Locale('zh', 'CN');
  
  Locale get locale => _locale;
  
  // 切换语言
  Future<void> switchLanguage(Locale newLocale) async {
    _locale = newLocale;
    
    // 保存到本地存储
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString('language_code', newLocale.languageCode);
    if (newLocale.countryCode != null) {
      await prefs.setString('country_code', newLocale.countryCode!);
    }
    
    // 通知监听者
    notifyListeners();
  }
  
  // 从本地存储加载语言设置
  Future<void> loadLanguageFromPrefs() async {
    final prefs = await SharedPreferences.getInstance();
    final languageCode = prefs.getString('language_code');
    final countryCode = prefs.getString('country_code');
    
    if (languageCode != null) {
      _locale = Locale(languageCode, countryCode);
      notifyListeners();
    }
  }
  
  // 获取支持的语言列表
  List<Map<String, dynamic>> get supportedLanguages => [
    {
      'code': 'zh',
      'country': 'CN',
      'name': '中文',
      'nativeName': '中文',
      'flag': '🇨🇳',
    },
    {
      'code': 'en',
      'country': 'US',
      'name': 'English',
      'nativeName': 'English',
      'flag': '🇺🇸',
    },
    {
      'code': 'ja',
      'country': 'JP',
      'name': 'Japanese',
      'nativeName': '日本語',
      'flag': '🇯🇵',
    },
    {
      'code': 'ko',
      'country': 'KR',
      'name': 'Korean',
      'nativeName': '한국어',
      'flag': '🇰🇷',
    },
  ];
  
  // 获取当前语言的显示名称
  String get currentLanguageName {
    final lang = supportedLanguages.firstWhere(
      (lang) => lang['code'] == _locale.languageCode,
      orElse: () => supportedLanguages.first,
    );
    return lang['name'];
  }
}

// 在应用入口配置
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  final languageManager = LanguageManager();
  final themeManager = ThemeManager();
  
  // 加载保存的设置
  await Future.wait([
    languageManager.loadLanguageFromPrefs(),
    themeManager.loadThemeFromPrefs(),
  ]);
  
  runApp(
    MultiProvider(
      providers: [
        ChangeNotifierProvider.value(value: languageManager),
        ChangeNotifierProvider.value(value: themeManager),
      ],
      child: const MyApp(),
    ),
  );
}

// 更新MyApp以支持动态语言切换
class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    final languageManager = Provider.of<LanguageManager>(context);
    final themeManager = Provider.of<ThemeManager>(context);
    
    return MaterialApp(
      title: 'Flutter国际化',
      theme: themeManager.currentTheme,
      // 使用动态locale
      locale: languageManager.locale,
      supportedLocales: const [
        Locale('en', 'US'),
        Locale('zh', 'CN'),
        Locale('ja', 'JP'),
        Locale('ko', 'KR'),
      ],
      localizationsDelegates: const [
        AppLocalizationsDelegate(),
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      localeResolutionCallback: (locale, supportedLocales) {
        return languageManager.locale;
      },
      home: const HomePage(),
    );
  }
}

3.4 语言切换界面

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

  @override
  Widget build(BuildContext context) {
    final languageManager = Provider.of<LanguageManager>(context);
    final localizations = AppLocalizations.of(context)!;
    
    return Scaffold(
      appBar: AppBar(
        title: Text(localizations.language),
      ),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          // 当前语言显示
          Card(
            child: Padding(
              padding: const EdgeInsets.all(16),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    localizations.currentLanguage,
                    style: const TextStyle(
                      fontSize: 16,
                      fontWeight: FontWeight.bold,
                    ),
                  ),
                  const SizedBox(height: 8),
                  Text(
                    languageManager.currentLanguageName,
                    style: const TextStyle(fontSize: 18),
                  ),
                ],
              ),
            ),
          ),
          const SizedBox(height: 24),
          
          // 语言选择列表
          Card(
            child: Padding(
              padding: const EdgeInsets.all(8),
              child: Column(
                children: languageManager.supportedLanguages.map((language) {
                  return ListTile(
                    leading: Text(
                      language['flag'],
                      style: const TextStyle(fontSize: 24),
                    ),
                    title: Text(language['nativeName']),
                    subtitle: Text(language['name']),
                    trailing: language['code'] == languageManager.locale.languageCode
                        ? const Icon(Icons.check, color: Colors.blue)
                        : null,
                    onTap: () {
                      languageManager.switchLanguage(
                        Locale(language['code'], language['country']),
                      );
                    },
                  );
                }).toList(),
              ),
            ),
          ),
          
          const SizedBox(height: 32),
          
          // 国际化功能
          _buildLocalizationDemo(context),
        ],
      ),
    );
  }
  
  Widget _buildLocalizationDemo(BuildContext context) {
    final localizations = AppLocalizations.of(context)!;
    final now = DateTime.now();
    final yesterday = now.subtract(const Duration(days: 1));
    
    return Card(
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(
              '国际化功能',
              style: Theme.of(context).textTheme.titleLarge,
            ),
            const SizedBox(height: 16),
            
            // 文本
            _buildDemoItem('普通文本', localizations.welcome),
            _buildDemoItem('带参数文本', localizations.welcomeUser('xx')),
            _buildDemoItem('按钮文本', localizations.submit),
            
            const SizedBox(height: 16),
            
            // 数字格式化
            _buildDemoItem('数字格式化', localizations.formatNumber(1234567)),
            _buildDemoItem('货币格式化', localizations.formatCurrency(1234.56)),
            
            const SizedBox(height: 16),
            
            // 日期格式化
            _buildDemoItem('日期格式化', localizations.formatDate(now)),
            _buildDemoItem('相对时间', localizations.formatRelativeTime(yesterday)),
          ],
        ),
      ),
    );
  }
  
  Widget _buildDemoItem(String label, String value) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 8),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            label,
            style: const TextStyle(
              fontSize: 12,
              color: Colors.grey,
            ),
          ),
          const SizedBox(height: 4),
          Text(
            value,
            style: const TextStyle(
              fontSize: 16,
              fontWeight: FontWeight.w500,
            ),
          ),
        ],
      ),
    );
  }
}

3.5 在Widget中使用国际化

class InternationalizedWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 获取本地化实例
    final localizations = AppLocalizations.of(context)!;
    
    return Scaffold(
      appBar: AppBar(
        title: Text(localizations.appTitle),
        actions: [
          IconButton(
            icon: const Icon(Icons.language),
            onPressed: () {
              Navigator.push(
                context,
                MaterialPageRoute(
                  builder: (context) => const LanguageSettingsPage(),
                ),
              );
            },
          ),
        ],
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              localizations.welcome,
              style: const TextStyle(fontSize: 24),
            ),
            const SizedBox(height: 20),
            
            // 使用本地化文本
            ElevatedButton(
              onPressed: () {},
              child: Text(localizations.login),
            ),
            const SizedBox(height: 10),
            
            OutlinedButton(
              onPressed: () {},
              child: Text(localizations.settings),
            ),
            const SizedBox(height: 10),
            
            TextButton(
              onPressed: () {
                // 显示本地化提示
                _showLocalizedDialog(context);
              },
              child: Text(localizations.info),
            ),
            
            const SizedBox(height: 30),
            
            // 显示格式化数据
            Text(
              '${localizations.currentLanguage}: ${localizations.formatNumber(1234)}',
              style: const TextStyle(fontSize: 16),
            ),
          ],
        ),
      ),
    );
  }
  
  void _showLocalizedDialog(BuildContext context) {
    final localizations = AppLocalizations.of(context)!;
    
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: Text(localizations.info),
        content: Text(localizations.welcomeUser('Flutter开发者')),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: Text(localizations.close),
          ),
          TextButton(
            onPressed: () {
              Navigator.pop(context);
              // ...
            },
            child: Text(localizations.confirm),
          ),
        ],
      ),
    );
  }
}

四、使用技巧

4.1 主题与国际化结合实践

创建配置管理器
// 统一的应用配置管理器
class AppConfigManager with ChangeNotifier {
  final ThemeManager _themeManager;
  final LanguageManager _languageManager;
  
  AppConfigManager({
    required ThemeManager themeManager,
    required LanguageManager languageManager,
  }) : _themeManager = themeManager,
       _languageManager = languageManager;
  
  // 同时切换主题和语言
  Future<void> switchToPreset(String presetName) async {
    switch (presetName) {
      case 'light_chinese':
        await _themeManager.switchTheme(ThemeModeType.light);
        await _languageManager.switchLanguage(const Locale('zh', 'CN'));
        break;
      case 'dark_english':
        await _themeManager.switchTheme(ThemeModeType.dark);
        await _languageManager.switchLanguage(const Locale('en', 'US'));
        break;
      // 这里还可以添加其他设置...
    }
    notifyListeners();
  }
  
  // 导出当前配置
  Map<String, dynamic> exportConfig() {
    return {
      'theme': _themeManager.themeMode.name,
      'language': _languageManager.locale.toString(),
      'timestamp': DateTime.now().toIso8601String(),
    };
  }
  
  // 导入配置
  Future<void> importConfig(Map<String, dynamic> config) async {
    // 解析并应用配置...
    notifyListeners();
  }
}

4.2 性能优化

按需加载语言资源
// 懒加载
class LazyAppLocalizations {
  static final Map<String, Future<Map<String, String>>> _resourceCache = {};
  
  static Future<Map<String, String>> _loadResources(String languageCode) async {
    // 接口调用
    await Future.delayed(const Duration(milliseconds: 100));
    return {
      'welcome': _getWelcomeText(languageCode),
      // ... 
    };
  }
  
  static Future<Map<String, String>> getResources(String languageCode) {
    if (!_resourceCache.containsKey(languageCode)) {
      _resourceCache[languageCode] = _loadResources(languageCode);
    }
    return _resourceCache[languageCode]!;
  }
  
  static String _getWelcomeText(String languageCode) {
    switch (languageCode) {
      case 'zh': return '欢迎';
      case 'en': return 'Welcome';
      default: return 'Welcome';
    }
  }
}
主题缓存
// 缓存
class ThemeCache {
  static final Map<String, ThemeData> _themeCache = {};
  
  static ThemeData getOrCreateTheme({
    required Color primaryColor,
    required Brightness brightness,
  }) {
    final key = '${primaryColor.value}_${brightness.name}';
    
    if (!_themeCache.containsKey(key)) {
      _themeCache[key] = ThemeData(
        colorScheme: ColorScheme.fromSeed(
          seedColor: primaryColor,
          brightness: brightness,
        ),
        useMaterial3: true,
      );
    }
    
    return _themeCache[key]!;
  }
}

4.3 测试策略

主题测试
// 主题
void testThemeSwitching() {
  final themeManager = ThemeManager();
  
  // 测试初始状态
  assert(themeManager.themeMode == ThemeModeType.system);
  
  // 测试切换主题
  themeManager.switchTheme(ThemeModeType.dark);
  assert(themeManager.themeMode == ThemeModeType.dark);
  
  // 测试自定义主题
  final customTheme = ThemeData(
    colorScheme: ColorScheme.fromSeed(seedColor: Colors.red),
  );
  themeManager.setCustomTheme(customTheme);
  assert(themeManager.themeMode == ThemeModeType.custom);
}

// Widget测试
void testThemedWidget() {
  testWidgets('Widget使用正确的主题颜色', (WidgetTester tester) async {
    await tester.pumpWidget(
      MaterialApp(
        theme: ThemeData(
          colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        ),
        home: ThemedWidget(),
      ),
    );
    
    // 验证Widget使用了主题颜色
    final container = tester.widget<Container>(
      find.byType(Container).first,
    );
    
    final boxDecoration = container.decoration as BoxDecoration;
  });
}

五、创建设置页面案例

// 整合主题和国际化的设置页面
class SettingsPage extends StatefulWidget {
  const SettingsPage({super.key});

  @override
  State<SettingsPage> createState() => _SettingsPageState();
}

class _SettingsPageState extends State<SettingsPage> {
  @override
  Widget build(BuildContext context) {
    final localizations = AppLocalizations.of(context)!;
    
    return Scaffold(
      appBar: AppBar(
        title: Text(localizations.settings),
      ),
      body: ListView(
        children: [
          // 用户信息
          _buildUserSection(context),
          
          // 主题设置
          _buildThemeSection(context),
          
          // 语言设置
          _buildLanguageSection(context),
          
          // 其他设置
          _buildOtherSettings(context),
          
          // 导出/导入配置
          _buildConfigManagement(context),
        ],
      ),
    );
  }
  
  Widget _buildUserSection(BuildContext context) {
    final localizations = AppLocalizations.of(context)!;
    
    return Card(
      margin: const EdgeInsets.all(16),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Row(
          children: [
            const CircleAvatar(
              radius: 30,
              backgroundImage: NetworkImage('https://via.placeholder.com/150'),
            ),
            const SizedBox(width: 16),
            Expanded(
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  Text(
                    '祁厅长',
                    style: Theme.of(context).textTheme.titleLarge,
                  ),
                  const SizedBox(height: 4),
                  Text(
                    'developer@example.com',
                    style: Theme.of(context).textTheme.bodyMedium?.copyWith(
                      color: Colors.grey,
                    ),
                  ),
                ],
              ),
            ),
            IconButton(
              icon: const Icon(Icons.edit),
              onPressed: () {
                // 编辑资料
              },
            ),
          ],
        ),
      ),
    );
  }
  
  Widget _buildThemeSection(BuildContext context) {
    final themeManager = Provider.of<ThemeManager>(context);
    final localizations = AppLocalizations.of(context)!;
    
    return Card(
      margin: const EdgeInsets.symmetric(horizontal: 16),
      child: ExpansionTile(
        leading: const Icon(Icons.color_lens),
        title: Text(localizations.theme),
        children: [
          Padding(
            padding: const EdgeInsets.all(16),
            child: Column(
              children: [
                // 主题模式选择
                _buildThemeModeSelector(themeManager, localizations),
                const SizedBox(height: 16),
                
                // 颜色选择器
                _buildColorSelector(themeManager),
                const SizedBox(height: 16),
                
                // 高级设置
                _buildAdvancedThemeSettings(themeManager, localizations),
              ],
            ),
          ),
        ],
      ),
    );
  }
  
  Widget _buildThemeModeSelector(
    ThemeManager themeManager, 
    AppLocalizations localizations,
  ) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          '主题模式',
          style: Theme.of(context).textTheme.titleMedium,
        ),
        const SizedBox(height: 8),
        SegmentedButton<ThemeModeType>(
          segments: [
            ButtonSegment(
              value: ThemeModeType.light,
              label: Text(localizations.lightMode),
              icon: const Icon(Icons.light_mode),
            ),
            ButtonSegment(
              value: ThemeModeType.dark,
              label: Text(localizations.darkMode),
              icon: const Icon(Icons.dark_mode),
            ),
            ButtonSegment(
              value: ThemeModeType.system,
              label: Text(localizations.systemMode),
              icon: const Icon(Icons.settings),
            ),
          ],
          selected: {themeManager.themeMode},
          onSelectionChanged: (Set<ThemeModeType> newSelection) {
            themeManager.switchTheme(newSelection.first);
          },
        ),
      ],
    );
  }
  
  Widget _buildColorSelector(ThemeManager themeManager) {
    final colors = [
      Colors.blue,
      Colors.green,
      Colors.red,
      Colors.purple,
      Colors.orange,
      Colors.teal,
    ];
    
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          '主题色',
          style: Theme.of(context).textTheme.titleMedium,
        ),
        const SizedBox(height: 8),
        Wrap(
          spacing: 12,
          runSpacing: 12,
          children: colors.map((color) {
            return GestureDetector(
              onTap: () {
                final isDark = themeManager.themeMode == ThemeModeType.dark;
                if (isDark) {
                  themeManager.updateDarkTheme(
                    ThemeData(
                      colorScheme: ColorScheme.fromSeed(
                        seedColor: color,
                        brightness: Brightness.dark,
                      ),
                    ),
                  );
                } else {
                  themeManager.updateLightTheme(
                    ThemeData(
                      colorScheme: ColorScheme.fromSeed(
                        seedColor: color,
                        brightness: Brightness.light,
                      ),
                    ),
                  );
                }
              },
              child: Container(
                width: 40,
                height: 40,
                decoration: BoxDecoration(
                  color: color,
                  shape: BoxShape.circle,
                  border: Border.all(
                    color: Theme.of(context).colorScheme.outline,
                    width: 2,
                  ),
                ),
              ),
            );
          }).toList(),
        ),
      ],
    );
  }
  
  Widget _buildAdvancedThemeSettings(
    ThemeManager themeManager,
    AppLocalizations localizations,
  ) {
    return ExpansionTile(
      title: const Text('高级设置'),
      children: [
        Padding(
          padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
          child: Column(
            children: [
              // 圆角设置
              _buildSliderSetting(
                '圆角大小',
                0.0,
                24.0,
                (value) {
                  // 更新主题圆角
                },
              ),
              
              // 阴影强度
              _buildSliderSetting(
                '阴影强度',
                0.0,
                10.0,
                (value) {
                  // 更新阴影
                },
              ),
              
              // 动画速度
              _buildSliderSetting(
                '动画速度',
                0.5,
                2.0,
                (value) {
                  // 更新动画速度
                },
              ),
            ],
          ),
        ),
      ],
    );
  }
  
  Widget _buildSliderSetting(
    String label,
    double min,
    double max,
    ValueChanged<double> onChanged,
  ) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 8),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(label),
          Slider(
            value: (min + max) / 2,
            min: min,
            max: max,
            onChanged: onChanged,
          ),
        ],
      ),
    );
  }
  
  Widget _buildLanguageSection(BuildContext context) {
    final languageManager = Provider.of<LanguageManager>(context);
    final localizations = AppLocalizations.of(context)!;
    
    return Card(
      margin: const EdgeInsets.all(16),
      child: ListTile(
        leading: const Icon(Icons.language),
        title: Text(localizations.language),
        subtitle: Text(languageManager.currentLanguageName),
        trailing: const Icon(Icons.chevron_right),
        onTap: () {
          Navigator.push(
            context,
            MaterialPageRoute(
              builder: (context) => const LanguageSettingsPage(),
            ),
          );
        },
      ),
    );
  }
  
  Widget _buildOtherSettings(BuildContext context) {
    final localizations = AppLocalizations.of(context)!;
    
    return Card(
      margin: const EdgeInsets.symmetric(horizontal: 16),
      child: Column(
        children: [
          ListTile(
            leading: const Icon(Icons.notifications),
            title: Text(localizations.notifications),
            trailing: Switch(
              value: true,
              onChanged: (value) {},
            ),
          ),
          const Divider(height: 1),
          ListTile(
            leading: const Icon(Icons.security),
            title: const Text('隐私设置'),
            trailing: const Icon(Icons.chevron_right),
            onTap: () {},
          ),
          const Divider(height: 1),
          ListTile(
            leading: const Icon(Icons.help),
            title: const Text('帮助与反馈'),
            trailing: const Icon(Icons.chevron_right),
            onTap: () {},
          ),
          const Divider(height: 1),
          ListTile(
            leading: const Icon(Icons.info),
            title: const Text('关于我们'),
            trailing: const Icon(Icons.chevron_right),
            onTap: () {},
          ),
        ],
      ),
    );
  }
  
  Widget _buildConfigManagement(BuildContext context) {
    return Card(
      margin: const EdgeInsets.all(16),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            const Text(
              '配置管理',
              style: TextStyle(
                fontSize: 18,
                fontWeight: FontWeight.bold,
              ),
            ),
            const SizedBox(height: 16),
            Row(
              children: [
                Expanded(
                  child: OutlinedButton.icon(
                    icon: const Icon(Icons.upload),
                    label: const Text('导出配置'),
                    onPressed: () {
                      _exportConfig(context);
                    },
                  ),
                ),
                const SizedBox(width: 16),
                Expanded(
                  child: OutlinedButton.icon(
                    icon: const Icon(Icons.download),
                    label: const Text('导入配置'),
                    onPressed: () {
                      _importConfig(context);
                    },
                  ),
                ),
              ],
            ),
            const SizedBox(height: 8),
            OutlinedButton.icon(
              icon: const Icon(Icons.restore),
              label: const Text('恢复默认设置'),
              onPressed: () {
                _resetToDefaults(context);
              },
            ),
          ],
        ),
      ),
    );
  }
  
  void _exportConfig(BuildContext context) {
    // 导出配置逻辑
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('导出配置'),
        content: const Text('配置已复制到剪贴板'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('确定'),
          ),
        ],
      ),
    );
  }
  
  void _importConfig(BuildContext context) {
    // 导入配置逻辑
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('导入配置'),
        content: const Text('请粘贴配置JSON'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('取消'),
          ),
          TextButton(
            onPressed: () {
              // 导入配置
              Navigator.pop(context);
            },
            child: const Text('导入'),
          ),
        ],
      ),
    );
  }
  
  void _resetToDefaults(BuildContext context) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('恢复默认设置'),
        content: const Text('确定要恢复所有设置为默认值吗?'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('取消'),
          ),
          TextButton(
            onPressed: () {
              // 恢复
              Navigator.pop(context);
            },
            child: const Text('确定'),
          ),
        ],
      ),
    );
  }
}

总结

至此主题与国际化相关知识点就介绍完了,通过本节内容的学习,我们掌握了以下核心知识点:主题系统动态主题切换国际化

实际开发建议

  1. 渐进式实现:如果项目已经开发到一半,可以从基础的主题配置开始,逐步添加国际化支持。

  2. 设计系统先行:在项目初期就建立完整的设计系统(Design System),包括颜色、字体、间距等规范。

  3. 保持一致性:确保整个应用使用统一的主题和国际化方案,避免混合使用不同方案。

  4. 用户体验优先:主题切换和语言切换应该流畅自然,提供良好的视觉效果。

OK!有任何问题或建议,欢迎在评论区留言讨论!让我们一起在Flutter全栈开发的道路上不断进步!

❌