Flutter&OpenHarmony主题切换功能实现

#

前言

主题切换功能是现代应用中提升用户体验的重要特性。用户可以根据个人喜好和使用环境选择不同的主题风格,如浅色主题、深色主题或跟随系统设置。对于笔记应用来说,合适的主题不仅能够保护用户视力,还能提供更舒适的阅读和编辑体验。本文将详细介绍如何在Flutter和OpenHarmony平台上实现完善的主题切换功能,包括主题定义、切换逻辑和持久化存储。

Flutter主题定义

Flutter通过ThemeData定义应用的主题样式。

dart 复制代码
class AppThemes {
  static final ThemeData lightTheme = ThemeData(
    brightness: Brightness.light,
    primarySwatch: Colors.blue,
    scaffoldBackgroundColor: Colors.white,
    appBarTheme: AppBarTheme(
      backgroundColor: Colors.white,
      foregroundColor: Colors.black,
      elevation: 0,
    ),
  );
}

ThemeData是Flutter中定义主题的核心类,它包含了应用中几乎所有组件的默认样式。brightness设置整体亮度模式,primarySwatch定义主色调,scaffoldBackgroundColor设置页面背景色。appBarTheme专门配置AppBar的样式,包括背景色、前景色和阴影高度。将主题定义为静态常量便于在应用中统一引用和管理。

dart 复制代码
static final ThemeData darkTheme = ThemeData(
  brightness: Brightness.dark,
  primarySwatch: Colors.blue,
  scaffoldBackgroundColor: Color(0xFF121212),
  appBarTheme: AppBarTheme(
    backgroundColor: Color(0xFF1E1E1E),
    foregroundColor: Colors.white,
    elevation: 0,
  ),
  cardColor: Color(0xFF1E1E1E),
  dividerColor: Color(0xFF2C2C2C),
);

深色主题需要仔细选择颜色值以确保良好的可读性和视觉舒适度。scaffoldBackgroundColor使用深灰色而非纯黑色,这是Material Design推荐的做法,可以减少视觉疲劳。cardColor和dividerColor等属性需要与背景色协调,形成层次分明的视觉效果。深色主题在夜间使用时可以有效减少屏幕亮度对眼睛的刺激。

主题状态管理

使用Provider或其他状态管理方案来管理主题状态。

dart 复制代码
class ThemeProvider extends ChangeNotifier {
  ThemeMode _themeMode = ThemeMode.system;
  
  ThemeMode get themeMode => _themeMode;
  
  void setThemeMode(ThemeMode mode) {
    _themeMode = mode;
    _saveThemePreference(mode);
    notifyListeners();
  }
  
  Future<void> _saveThemePreference(ThemeMode mode) async {
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString('themeMode', mode.toString());
  }
}

ThemeProvider继承ChangeNotifier,这是Flutter中实现响应式状态管理的基础类。_themeMode存储当前的主题模式,支持light、dark和system三种模式。setThemeMode方法更新主题模式,同时将设置保存到SharedPreferences中实现持久化,最后调用notifyListeners通知所有监听者更新UI。这种设计使得主题切换可以即时生效,并且在应用重启后保持用户的选择。

dart 复制代码
Future<void> loadThemePreference() async {
  final prefs = await SharedPreferences.getInstance();
  final savedMode = prefs.getString('themeMode');
  if (savedMode != null) {
    if (savedMode.contains('light')) {
      _themeMode = ThemeMode.light;
    } else if (savedMode.contains('dark')) {
      _themeMode = ThemeMode.dark;
    } else {
      _themeMode = ThemeMode.system;
    }
    notifyListeners();
  }
}

loadThemePreference方法在应用启动时调用,从SharedPreferences读取保存的主题设置。通过字符串匹配来解析ThemeMode枚举值,这种方式简单可靠。加载完成后调用notifyListeners确保UI使用正确的主题。这个方法通常在应用初始化阶段调用,确保用户看到的第一个界面就是正确的主题。

OpenHarmony主题实现

OpenHarmony通过资源文件和状态管理实现主题切换。

typescript 复制代码
interface ThemeColors {
  primary: string
  background: string
  surface: string
  textPrimary: string
  textSecondary: string
  divider: string
}

const LightTheme: ThemeColors = {
  primary: '#1890FF',
  background: '#FFFFFF',
  surface: '#F5F5F5',
  textPrimary: '#333333',
  textSecondary: '#666666',
  divider: '#EEEEEE'
}

const DarkTheme: ThemeColors = {
  primary: '#1890FF',
  background: '#121212',
  surface: '#1E1E1E',
  textPrimary: '#FFFFFF',
  textSecondary: '#AAAAAA',
  divider: '#2C2C2C'
}

OpenHarmony中可以通过定义主题颜色接口来管理主题样式。ThemeColors接口定义了主题中需要的各种颜色,包括主色、背景色、表面色、文字颜色和分隔线颜色。LightTheme和DarkTheme分别定义浅色和深色主题的具体颜色值。这种结构化的定义方式使得主题管理更加清晰,添加新的颜色属性也很方便。

typescript 复制代码
@Observed
class ThemeManager {
  currentTheme: ThemeColors = LightTheme
  isDarkMode: boolean = false
  
  toggleTheme() {
    this.isDarkMode = !this.isDarkMode
    this.currentTheme = this.isDarkMode ? DarkTheme : LightTheme
    this.saveThemePreference()
  }
  
  async saveThemePreference() {
    let pref = await preferences.getPreferences(getContext(), 'settings')
    await pref.put('isDarkMode', this.isDarkMode)
    await pref.flush()
  }
}

ThemeManager类使用@Observed装饰器使其成为可观察对象,当属性变化时会自动触发UI更新。toggleTheme方法切换主题模式,同时更新currentTheme和isDarkMode属性。saveThemePreference方法将主题设置保存到Preferences中,确保应用重启后能够恢复用户的选择。这种集中管理主题状态的方式使得主题切换逻辑清晰可控。

主题切换界面

提供直观的主题切换界面让用户选择偏好的主题。

dart 复制代码
class ThemeSettingsPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<ThemeProvider>(
      builder: (context, themeProvider, child) {
        return Column(
          children: [
            RadioListTile<ThemeMode>(
              title: Text('浅色模式'),
              value: ThemeMode.light,
              groupValue: themeProvider.themeMode,
              onChanged: (mode) => themeProvider.setThemeMode(mode!),
            ),
            RadioListTile<ThemeMode>(
              title: Text('深色模式'),
              value: ThemeMode.dark,
              groupValue: themeProvider.themeMode,
              onChanged: (mode) => themeProvider.setThemeMode(mode!),
            ),
            RadioListTile<ThemeMode>(
              title: Text('跟随系统'),
              value: ThemeMode.system,
              groupValue: themeProvider.themeMode,
              onChanged: (mode) => themeProvider.setThemeMode(mode!),
            ),
          ],
        );
      },
    );
  }
}

主题设置页面使用Consumer监听ThemeProvider的变化。RadioListTile提供了单选列表项的标准样式,非常适合主题选择场景。三个选项分别对应浅色模式、深色模式和跟随系统。groupValue绑定当前选中的主题模式,onChanged回调在用户选择时更新主题。跟随系统选项让应用能够自动适应系统的深色模式设置,这是现代应用的标准功能。

OpenHarmony主题设置

typescript 复制代码
@Entry
@Component
struct ThemeSettingsPage {
  @StorageLink('themeManager') themeManager: ThemeManager = new ThemeManager()
  
  build() {
    Column() {
      Text('主题设置')
        .fontSize(20)
        .fontWeight(FontWeight.Bold)
        .margin({ bottom: 20 })
      
      Row() {
        Text('深色模式')
          .fontSize(16)
        Blank()
        Toggle({ type: ToggleType.Switch, isOn: this.themeManager.isDarkMode })
          .onChange((isOn: boolean) => {
            this.themeManager.toggleTheme()
          })
      }
      .width('100%')
      .padding(15)
      .backgroundColor(this.themeManager.currentTheme.surface)
      .borderRadius(8)
    }
    .width('100%')
    .height('100%')
    .padding(20)
    .backgroundColor(this.themeManager.currentTheme.background)
  }
}

OpenHarmony的主题设置页面使用@StorageLink装饰器连接全局的ThemeManager实例。Toggle组件提供开关样式的交互,isOn属性绑定当前的深色模式状态。onChange回调在用户切换开关时调用toggleTheme方法。页面的背景色和组件颜色都从currentTheme中获取,确保主题切换后界面能够即时更新。这种数据驱动的方式使得主题切换的实现非常简洁。

应用主题配置

在应用入口配置主题以使其全局生效。

dart 复制代码
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<ThemeProvider>(
      builder: (context, themeProvider, child) {
        return MaterialApp(
          theme: AppThemes.lightTheme,
          darkTheme: AppThemes.darkTheme,
          themeMode: themeProvider.themeMode,
          home: HomePage(),
        );
      },
    );
  }
}

MaterialApp的theme属性设置浅色主题,darkTheme设置深色主题,themeMode控制使用哪个主题。当themeMode为ThemeMode.system时,应用会根据系统设置自动选择主题。Consumer确保当ThemeProvider的状态变化时,MaterialApp会重新构建并应用新的主题。这种配置方式使得主题切换对整个应用生效,所有页面都会使用统一的主题样式。

总结

主题切换功能是提升用户体验的重要特性,Flutter和OpenHarmony都提供了完善的主题支持。开发者需要合理定义主题样式、实现状态管理和持久化存储,才能为用户提供流畅的主题切换体验。深色模式不仅是视觉偏好,更是保护用户视力的重要功能,值得每个应用认真实现。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

相关推荐
一路向北North2 小时前
java 下载文件中文名乱码
java·开发语言·python
skywalk81632 小时前
Python虚拟环境自动激活:使用激活脚本 `activate_venv.ps1` ,每次打开终端后运行 ./activate_venv.ps1即可
开发语言·python
沛沛老爹2 小时前
2025年AI冲击下的Java Web开发现状
java·开发语言·人工智能·程序人生·职场和发展·年度总结
资生算法程序员_畅想家_剑魔2 小时前
Java常见技术分享-21-多线程安全-进阶模块-并发集合与线程池-ForkJoinPool
java·开发语言
Cx330❀2 小时前
《C++ 递归、搜索与回溯》第1题:汉诺塔问题
开发语言·c++·算法·面试·回归算法
C_心欲无痕2 小时前
react - useReducer复杂状态管理
前端·javascript·react.js
superman超哥2 小时前
Rust Profile-Guided Optimization(PGO):数据驱动的极致性能优化
开发语言·后端·性能优化·rust·数据驱动·pgo
草莓熊Lotso2 小时前
Qt 入门核心指南:从框架认知到环境搭建 + Qt Creator 实战
xml·开发语言·网络·c++·人工智能·qt·页面
微爱帮监所写信寄信2 小时前
微爱帮监狱寄信邮票真伪核实接口认证方案
开发语言·python