前言:

一款实用的“口袋工具”,不仅要满足核心功能需求,更要在细节体验上贴近用户习惯。深色模式便是这样一个高频提及的优化点——在暗色环境下对比度不足、提示色不统一。正是这些真实的使用场景,促使我选择“深色模式适配”作为本篇文章的内容。

本文参考

【2025版 OpenHarmony】GitCode 口袋工具 v1.0.3:Flutter + HarmonyOS 深色模式全面启用_边框阴影openharmony-CSDN博客

本文记录操作流程以及遇到的问题

一、前期准备工作

为便于用户快速切换主题模式,首先需在应用面板中添加深色模式控制入口,操作步骤如下:

  • 下滑打开应用功能面板,点击红色箭头所指的【添加功能】图标;​
  • 在功能列表中找到“深色模式”选项,点击【加号】完成添加;​
  • 预期效果:功能面板中显示深色模式开关,支持手动切换及系统主题同步。

先把深色模式添加到面板上

下滑打开,点击红色箭头所指的图标:

点击加号,添加深色模式:

预期完成效果如下:

二、核心实现:主题配置与代码改造

本次适配以“lib/core/app_theme.dart”为核心配置文件,通过封装浅色/深色主题的'ThemeData',实现全应用视觉风格的统一管理。同时修改主入口及各页面代码,确保主题配置生效。

2.1 核心配置:新建app_theme.dart主题管理类

lib/core/app_theme.dart 是本次修改的核心,它封装了浅色/深色的 ThemeData,包含导航栏、卡片、输入框、Chip 等子主题。后续如需定制新的组件,只需在这里统一配置。

新建app_theme.dart文件

在项目文件\lib\core新建app_theme.dart文件,添加内容:

import 'package:flutter/material.dart';

/// 统一管理浅色(Light)与深色(Dark)主题的工具类。
/// 通过 Material 3 的 ColorScheme.fromSeed 自动生成协调配色,
/// 并为常用组件(AppBar、Card、Input 等)定制统一的视觉风格。
/// 特别适用于需要适配系统夜间模式的场景(如 HarmonyOS)。
class AppTheme {
  // 私有构造函数:防止外部实例化此类(仅作为静态工具类使用)
  AppTheme._();

  /// 主题的“种子颜色”(Seed Color)。
  /// Material 3 会基于此颜色自动生成整套配色方案(primary、onPrimary、surface 等)。
  /// 这里使用 Indigo(靛蓝)作为主色调,可根据需求替换。
  static const Color _seedColor = Colors.indigo;

  /// 返回浅色主题(Brightness.light)
  static ThemeData light() => _theme(Brightness.light);

  /// 返回深色主题(Brightness.dark)
  static ThemeData dark() => _theme(Brightness.dark);

  /// 内部私有方法:根据指定的亮度(亮/暗)生成完整的 ThemeData 主题配置。
  ///
  /// [brightness]:指定主题是亮色还是暗色。
  static ThemeData _theme(Brightness brightness) {
    // 基于种子色和亮度,自动生成一套符合 Material 3 规范的配色方案
    final colorScheme = ColorScheme.fromSeed(
      seedColor: _seedColor,
      brightness: brightness, // 决定生成的是浅色还是深色配色
    );

    // 判断当前是否为深色模式,用于后续微调某些颜色的透明度
    final isDark = brightness == Brightness.dark;

    // 构建完整的 ThemeData 对象
    return ThemeData(
      // 使用自动生成的配色方案
      colorScheme: colorScheme,

      // 启用 Material Design 3(Material You)风格
      useMaterial3: true,

      // 设置视觉密度为标准(不压缩 UI 元素间距)
      visualDensity: VisualDensity.standard,

      // 明确指定主题亮度(影响滚动条、弹窗等系统组件)
      brightness: brightness,

      // Scaffold 背景色使用 surface(Material 3 中代表“纸张”表面的颜色)
      scaffoldBackgroundColor: colorScheme.surface,

      // 配置 AppBar(顶部导航栏)样式
      appBarTheme: AppBarTheme(
        backgroundColor: colorScheme.surface,           // 背景使用 surface 色
        foregroundColor: colorScheme.onSurface,         // 文字/图标使用 onSurface 色
        centerTitle: true,                              // 标题居中
        elevation: 0,                                   // 无阴影(M3 推荐用颜色区分层级而非阴影)
      ),

      // 配置底部导航栏(NavigationBar)样式
      navigationBarTheme: NavigationBarThemeData(
        backgroundColor: colorScheme.surfaceContainerHigh, // 使用高一级容器色,略深于 surface
        indicatorColor: colorScheme.primary.withOpacity(
          isDark ? 0.35 : 0.2, // 深色模式下指示器更不透明,保证可见性
        ),
        labelBehavior: NavigationDestinationLabelBehavior.alwaysShow, // 始终显示标签文字
      ),

      // 配置 Card(卡片)样式
      cardTheme: CardTheme(
        color: colorScheme.surfaceContainerLowest, // 最浅的容器色,用于卡片背景
        elevation: 0, // 无阴影(靠颜色层次表达层级)
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(20), // 圆角 20,现代感强
        ),
      ),

      // 配置输入框(TextField 等)的装饰样式
      inputDecorationTheme: InputDecorationTheme(
        // 默认边框样式(未聚焦)
        border: OutlineInputBorder(
          borderRadius: BorderRadius.circular(16),
          borderSide: BorderSide(color: colorScheme.outlineVariant),
        ),
        // 启用状态下的边框(同默认)
        enabledBorder: OutlineInputBorder(
          borderRadius: BorderRadius.circular(16),
          borderSide: BorderSide(color: colorScheme.outlineVariant),
        ),
        // 聚焦状态下的边框(高亮主色)
        focusedBorder: OutlineInputBorder(
          borderRadius: BorderRadius.circular(16),
          borderSide: BorderSide(color: colorScheme.primary, width: 1.4),
        ),
        filled: true, // 启用填充背景
        fillColor: colorScheme.surfaceContainerLowest, // 填充色使用最浅容器色
        // 标签文字颜色(如 "用户名")
        labelStyle: TextStyle(color: colorScheme.onSurfaceVariant),
        // 提示文字颜色(如 "请输入..."),稍透明
        hintStyle: TextStyle(color: colorScheme.onSurfaceVariant.withOpacity(0.7)),
        // 前缀图标颜色(如 🔍)
        prefixIconColor: colorScheme.onSurfaceVariant,
      ),

      // 配置 Chip(标签/徽章)样式
      chipTheme: ChipThemeData(
        backgroundColor: colorScheme.surfaceContainerHigh, // 背景色
        selectedColor: colorScheme.primary.withOpacity(0.2), // 选中时的半透主色背景
        shape: RoundedRectangleBorder(
          borderRadius: BorderRadius.circular(24), // 更大圆角,柔和
        ),
        labelStyle: TextStyle(color: colorScheme.onSurface), // 文字颜色
      ),

      // 配置 Divider(分割线)样式
      dividerTheme: DividerThemeData(
        color: colorScheme.outlineVariant.withOpacity(0.7), // 使用 outlineVariant 并降低透明度
        thickness: 1, // 线条粗细
      ),
    );
  }
}

1.2 修改main.dart文件

只需在lib/main.dart 引用AppTheme,即可同时用有亮色/暗色主题,并通过ThemeMode.system跟随HarmonyOS/Windows的系统设置。

记得添加导入文件

import 'package:gitcode_pocket_tool/core/app_theme.dart';

原代码:

 return MaterialApp(
      title: 'GitCode 口袋工具',
      theme: ThemeData(
        colorSchemeSeed: Colors.indigo,
        useMaterial3: true,
        visualDensity: VisualDensity.standard,
      ),
      home: const MainNavigationPage(),
      debugShowCheckedModeBanner: false,
    );

修改代码:

return MaterialApp(
  title: 'GitCode 口袋工具',
  theme: AppTheme.light(),
  darkTheme: AppTheme.dark(),
  themeMode: ThemeMode.system,
  home: const MainNavigationPage(),
);

1.3 搜索页提示组件

1.3.1 修改search_page.dart文件

删除硬编码的 Colors.grey/Colors.red 等写法,统一改为从 Theme.of (context).colorScheme 中读取语义化颜色,确保亮 / 暗模式下的视觉表现保持一致。

路径:项目名称\lib\pages\main_navigation\search_page.dart

原代码:

 return _InfoBanner(
        icon: Icons.error_outline,
        background: Colors.red.withValues(alpha: 0.08),
        textColor: Colors.red.shade700,
        message: _errorMessage!,
      );

修改代码:

return _InfoBanner(
  icon: Icons.error_outline,
  background: scheme.errorContainer,
  textColor: scheme.onErrorContainer,
  message: _errorMessage!,
);

1.3.2 搜索页:解决变量未定义问题

路径:lib/pages/main_navigation/search_page.dart,改造提示组件颜色配置,过程中遇到“scheme”变量未定义的报错,解决方案如下:

  • 问题复现:search_page.dart 中 scheme 变量未定义
  • 原因是没在 _SearchPageState 类中声明 scheme 变量,导致代码引用了不存在的标识符

解决方法:

  • 先传入 context,再通过 Theme.of(context) 获取 ColorScheme

新增代码:

final ColorScheme scheme = Theme.of(context).colorScheme;

三、完成效果展示

后续更新方向:

  • 直接在 HarmonyOS/Windows 环境运行(无需额外配置),即可体验自动夜间模式
  • 若需自定义配色,只需在 AppTheme 中调整 seedColor 或子主题
  • 收藏/历史功能
  • 数据缓存与离线模式

四、总结:

工具类应用的价值不在于复杂的功能堆砌,而在于对用户痛点的精准回应。深色模式的适配看似是一个“小功能”,却需要在技术实现与用户体验之间找到最佳平衡。未来,我计划基于本次开发经验,为应用添加更多实用功能模块,同时持续跟进Flutter与HarmonyOS的技术更新。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐