色盲模拟器应用
欢迎加入开源鸿蒙跨平台社区:
https://openharmonycrossplatform.csdn.net
一、项目概述
运行效果图





1.1 应用简介
色盲模拟器应用是一款面向设计师和开发者的无障碍设计工具,旨在帮助用户了解色盲人群的视觉体验,从而设计出更加友好的无障碍产品。应用以蓝色为主色调,体现专业与关怀的设计理念。
应用涵盖了色盲模拟、调色板对比、对比度检测、色盲知识四大模块,支持8种色盲类型的模拟,提供实时颜色转换、WCAG对比度检测、常见UI场景示例等功能。通过直观的颜色对比展示,帮助设计师理解色盲用户的视觉差异,优化设计方案。
1.2 核心功能
| 功能模块 | 功能描述 | 实现方式 |
|---|---|---|
| 色盲模拟 | 8种色盲类型模拟 | 颜色矩阵转换 |
| 调色板对比 | 常见颜色组合展示 | 双列对比卡片 |
| 对比度检测 | WCAG标准检测 | 亮度计算公式 |
| UI示例 | 真实场景模拟 | 组件对比展示 |
| 色盲知识 | 科普教育内容 | 信息卡片 |
1.3 色盲类型
| 序号 | 类型名称 | 英文名 | 发生率 | 描述 |
|---|---|---|---|---|
| 1 | 正常视觉 | Normal | - | 全色觉,能够分辨所有颜色 |
| 2 | 红色盲 | Protanopia | 约1%男性 | 无法分辨红色,红色呈现为暗黄色 |
| 3 | 绿色盲 | Deuteranopia | 约1%男性 | 无法分辨绿色,绿色呈现为黄色 |
| 4 | 蓝色盲 | Tritanopia | 极罕见 | 无法分辨蓝色,蓝色呈现为绿色 |
| 5 | 全色盲 | Achromatopsia | 极罕见 | 只能看到黑白灰,无法分辨任何颜色 |
| 6 | 红色弱 | Protanomaly | 约1%男性 | 红色感知减弱,红色呈现较淡 |
| 7 | 绿色弱 | Deuteranomaly | 约5%男性 | 绿色感知减弱,绿色呈现较淡 |
| 8 | 蓝色弱 | Tritanomaly | 极罕见 | 蓝色感知减弱,蓝色呈现较淡 |
1.4 技术栈
| 技术领域 | 技术选型 | 版本要求 |
|---|---|---|
| 开发框架 | Flutter | >= 3.0.0 |
| 编程语言 | Dart | >= 2.17.0 |
| 设计规范 | Material Design 3 | - |
| 颜色计算 | 矩阵变换 | - |
| 状态管理 | setState | - |
| 目标平台 | 鸿蒙OS / Web | API 21+ |
1.5 项目结构
lib/
└── main_colorblind_simulator.dart
├── ColorblindSimulatorApp # 应用入口
├── ColorblindType # 色盲类型枚举
├── ColorblindSimulatorHomePage # 主页面
├── _simulateColorblind # 颜色转换算法
├── _calculateContrastRatio # 对比度计算
├── _buildSimulatorPage # 模拟页面
├── _buildColorPalettePage # 调色板页面
├── _buildContrastPage # 对比度页面
└── _buildInfoPage # 知识页面
二、系统架构
2.1 整体架构图
Data Layer
Algorithm Layer
Presentation Layer
主页面
ColorblindSimulatorHomePage
模拟页面
调色板页面
对比度页面
知识页面
类型选择器
颜色对比
UI示例
颜色组合
颜色信息
标准说明
对比度卡片
科普知识
_simulateColorblind
颜色转换
_calculateContrastRatio
对比度计算
_getContrastLevel
等级判定
ColorblindType
色盲类型
测试颜色列表
颜色组合数据
UI示例数据
2.2 类图设计
uses
ColorblindSimulatorApp
+Widget build()
<<enumeration>>
ColorblindType
+String label
+String description
+IconData icon
+Color color
+normal()
+protanopia()
+deuteranopia()
+tritanopia()
+achromatopsia()
+protanomaly()
+deuteranomaly()
+tritanomaly()
ColorblindSimulatorHomePage
-int _selectedIndex
-ColorblindType _selectedType
-List<Color> _testColors
-List<Map> _colorPairs
-List<Map> _uiExamples
+Widget build()
-_simulateColorblind()
-_calculateContrastRatio()
-_getContrastLevel()
2.3 页面导航流程
模拟
调色板
对比度
说明
应用启动
模拟页面
底部导航
色盲类型选择
颜色对比展示
UI场景示例
颜色组合列表
颜色转换对比
WCAG标准说明
对比度检测卡片
色盲知识科普
2.4 颜色转换流程
转换算法 模拟器 用户 转换算法 模拟器 用户 选择色盲类型 更新选中状态 查看颜色对比 传入原始颜色 应用转换矩阵 返回转换后颜色 展示对比效果
三、核心模块设计
3.1 色盲类型枚举设计
3.1.1 色盲类型枚举 (ColorblindType)
dart
enum ColorblindType {
normal('正常视觉', '全色觉,能够分辨所有颜色', Icons.visibility, Color(0xFF4CAF50)),
protanopia('红色盲', '无法分辨红色,红色呈现为暗黄色', Icons.color_lens, Color(0xFFF44336)),
deuteranopia('绿色盲', '无法分辨绿色,绿色呈现为黄色', Icons.grass, Color(0xFF8BC34A)),
tritanopia('蓝色盲', '无法分辨蓝色,蓝色呈现为绿色', Icons.water_drop, Color(0xFF2196F3)),
achromatopsia('全色盲', '只能看到黑白灰,无法分辨任何颜色', Icons.gradient, Color(0xFF9E9E9E)),
protanomaly('红色弱', '红色感知减弱,红色呈现较淡', Icons.visibility_off, Color(0xFFE57373)),
deuteranomaly('绿色弱', '绿色感知减弱,绿色呈现较淡', Icons.nature, Color(0xFFAED581)),
tritanomaly('蓝色弱', '蓝色感知减弱,蓝色呈现较淡', Icons.pool, Color(0xFF64B5F6));
final String label; // 类型名称
final String description; // 类型描述
final IconData icon; // 类型图标
final Color color; // 主题颜色
}
3.1.2 色盲类型分布
92% 5% 1% 1% 1% 色盲类型分布(男性) 绿色弱 红色弱 红色盲 绿色盲 正常视觉
3.2 颜色转换算法
3.2.1 红色盲转换矩阵
dart
case ColorblindType.protanopia:
newR = 0.567 * r + 0.433 * g + 0.0 * b;
newG = 0.558 * r + 0.442 * g + 0.0 * b;
newB = 0.0 * r + 0.242 * g + 0.758 * b;
break;
3.2.2 绿色盲转换矩阵
dart
case ColorblindType.deuteranopia:
newR = 0.625 * r + 0.375 * g + 0.0 * b;
newG = 0.7 * r + 0.3 * g + 0.0 * b;
newB = 0.0 * r + 0.3 * g + 0.7 * b;
break;
3.2.3 蓝色盲转换矩阵
dart
case ColorblindType.tritanopia:
newR = 0.95 * r + 0.05 * g + 0.0 * b;
newG = 0.0 * r + 0.433 * g + 0.567 * b;
newB = 0.0 * r + 0.475 * g + 0.525 * b;
break;
3.2.4 全色盲转换
dart
case ColorblindType.achromatopsia:
final gray = 0.299 * r + 0.587 * g + 0.114 * b;
newR = gray;
newG = gray;
newB = gray;
break;
3.3 对比度计算
3.3.1 亮度计算公式
dart
double getLuminance(Color color) {
final r = color.red / 255.0;
final g = color.green / 255.0;
final b = color.blue / 255.0;
final rLinear = r <= 0.03928 ? r / 12.92 : pow((r + 0.055) / 1.055, 2.4);
final gLinear = g <= 0.03928 ? g / 12.92 : pow((g + 0.055) / 1.055, 2.4);
final bLinear = b <= 0.03928 ? b / 12.92 : pow((b + 0.055) / 1.055, 2.4);
return 0.2126 * rLinear + 0.7152 * gLinear + 0.0722 * bLinear;
}
3.3.2 对比度计算
dart
double _calculateContrastRatio(Color color1, Color color2) {
final l1 = getLuminance(color1);
final l2 = getLuminance(color2);
final lighter = max(l1, l2);
final darker = min(l1, l2);
return (lighter + 0.05) / (darker + 0.05);
}
3.4 页面结构设计
3.4.1 模拟页面结构
模拟页面
SliverAppBar
类型选择器
颜色对比
UI示例
渐变背景
标题文字
类型网格
描述卡片
正常视觉
模拟效果
成功/错误
警告/信息
在线/离线
优先级标识
3.4.2 对比度页面结构
对比度页面
标准说明卡片
对比度列表
AAA标准
AA标准
AA Large标准
颜色组合卡片
正常对比度
模拟对比度
四、UI设计规范
4.1 配色方案
应用采用蓝色为主色调,体现专业与关怀:
| 颜色类型 | 色值 | 用途 |
|---|---|---|
| 主色 | #2196F3 (Blue) | 导航、强调元素 |
| 正常视觉 | #4CAF50 | 绿色 |
| 红色盲 | #F44336 | 红色 |
| 绿色盲 | #8BC34A | 浅绿 |
| 蓝色盲 | #2196F3 | 蓝色 |
| 全色盲 | #9E9E9E | 灰色 |
4.2 WCAG对比度标准
| 等级 | 对比度要求 | 适用场景 |
|---|---|---|
| AAA | ≥ 7.0 | 优秀级别,适合所有用户 |
| AA | ≥ 4.5 | 良好级别,普通文本 |
| AA Large | ≥ 3.0 | 一般级别,大文本 |
| 不达标 | < 3.0 | 需要改进 |
4.3 字体规范
| 元素 | 字号 | 字重 | 颜色 |
|---|---|---|---|
| 页面标题 | 20px | Bold | #000000 |
| 类型名称 | 13px | Bold/Normal | 主题色 |
| 对比度数值 | 18px | Bold | 等级颜色 |
| 描述文字 | 12px | Normal | #666666 |
4.4 组件规范
4.4.1 类型选择卡片
┌─────────────────────┐
│ 👁️ 正常视觉 │
└─────────────────────┘
4.4.2 颜色对比卡片
┌─────────────────────────────────────────────────┐
│ 正常视觉 │ 红色盲 │
│ ┌────┬────┬────┬────┐│ ┌────┬────┬────┬────┐│
│ │红 │绿 │蓝 │黄 ││ │██│██│██│██││
│ └────┴────┴────┴────┘│ └────┴────┴────┴────┘│
└─────────────────────────────────────────────────┘
4.4.3 对比度卡片
┌─────────────────────────────────────────────────┐
│ 红绿对比 │
│ │
│ 正常视觉 │ 红色盲 │
│ ┌────────┐ │ ┌────────┐ │
│ │红 │绿 │ │ │██│██│ │
│ └────────┘ │ └────────┘ │
│ 1.28 │ 1.05 │
│ [不达标] │ [不达标] │
└─────────────────────────────────────────────────┘
五、核心功能实现
5.1 颜色转换算法
dart
Color _simulateColorblind(Color color, ColorblindType type) {
if (type == ColorblindType.normal) return color;
final r = color.red / 255.0;
final g = color.green / 255.0;
final b = color.blue / 255.0;
double newR, newG, newB;
switch (type) {
case ColorblindType.protanopia:
newR = 0.567 * r + 0.433 * g + 0.0 * b;
newG = 0.558 * r + 0.442 * g + 0.0 * b;
newB = 0.0 * r + 0.242 * g + 0.758 * b;
break;
// ... 其他类型
}
return Color.fromRGBO(
(newR.clamp(0.0, 1.0) * 255).round(),
(newG.clamp(0.0, 1.0) * 255).round(),
(newB.clamp(0.0, 1.0) * 255).round(),
color.opacity,
);
}
5.2 对比度计算
dart
double _calculateContrastRatio(Color color1, Color color2) {
double getLuminance(Color color) {
final r = color.red / 255.0;
final g = color.green / 255.0;
final b = color.blue / 255.0;
final rLinear = r <= 0.03928 ? r / 12.92 : pow((r + 0.055) / 1.055, 2.4);
final gLinear = g <= 0.03928 ? g / 12.92 : pow((g + 0.055) / 1.055, 2.4);
final bLinear = b <= 0.03928 ? b / 12.92 : pow((b + 0.055) / 1.055, 2.4);
return 0.2126 * rLinear + 0.7152 * gLinear + 0.0722 * bLinear;
}
final l1 = getLuminance(color1);
final l2 = getLuminance(color2);
final lighter = max(l1, l2);
final darker = min(l1, l2);
return (lighter + 0.05) / (darker + 0.05);
}
5.3 对比度等级判定
dart
String _getContrastLevel(double ratio) {
if (ratio >= 7.0) return 'AAA (优秀)';
if (ratio >= 4.5) return 'AA (良好)';
if (ratio >= 3.0) return 'AA Large (一般)';
return '不达标';
}
5.4 类型选择器实现
dart
GridView.count(
shrinkWrap: true,
crossAxisCount: 2,
mainAxisSpacing: 8,
crossAxisSpacing: 8,
childAspectRatio: 2.5,
children: ColorblindType.values.map((type) {
final isSelected = _selectedType == type;
return GestureDetector(
onTap: () => setState(() => _selectedType = type),
child: AnimatedContainer(
duration: const Duration(milliseconds: 200),
decoration: BoxDecoration(
color: isSelected ? type.color.withValues(alpha: 0.15) : Colors.grey.shade100,
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: isSelected ? type.color : Colors.transparent,
width: 2,
),
),
child: Row(
children: [
Icon(type.icon, color: type.color),
Text(type.label),
],
),
),
);
}).toList(),
)
六、交互设计
6.1 类型选择流程
视图 模拟器 用户 视图 模拟器 用户 点击类型卡片 更新_selectedType 重新渲染颜色对比 应用颜色转换 显示模拟效果
6.2 颜色转换流程
红色盲
绿色盲
蓝色盲
全色盲
色弱
原始颜色
选择色盲类型
应用红色盲矩阵
应用绿色盲矩阵
应用蓝色盲矩阵
灰度转换
应用色弱矩阵
输出转换颜色
6.3 对比度检测流程
选择颜色组合
计算亮度
计算对比度
判定等级
显示结果
七、扩展功能规划
7.1 后续版本规划
2024-01-07 2024-01-14 2024-01-21 2024-01-28 2024-02-04 2024-02-11 2024-02-18 2024-02-25 2024-03-03 2024-03-10 2024-03-17 2024-03-24 色盲类型模拟 对比度检测 UI场景示例 图片上传 实时相机 配色建议 色盲友好配色生成 设计稿检测 团队协作 V1.0 基础版本 V1.1 增强版本 V1.2 进阶版本 色盲模拟器应用开发计划
7.2 功能扩展建议
7.2.1 图片上传
图片模拟功能:
- 上传设计稿图片
- 实时应用色盲滤镜
- 导出模拟效果图
7.2.2 实时相机
实时预览功能:
- 打开摄像头预览
- 实时应用色盲滤镜
- 截图保存效果
7.2.3 配色建议
智能配色功能:
- 分析当前配色问题
- 提供色盲友好替代方案
- 自动生成配色方案
八、注意事项
8.1 开发注意事项
-
颜色转换:使用矩阵乘法实现精确转换
-
亮度计算:使用sRGB标准公式
-
对比度:遵循WCAG 2.1标准
-
性能优化:避免重复计算,缓存转换结果
8.2 常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 颜色转换不准确 | 矩阵参数错误 | 检查转换矩阵 |
| 对比度计算错误 | 亮度公式错误 | 使用标准公式 |
| 等级判定不准 | 阈值设置错误 | 参考WCAG标准 |
| UI显示异常 | 颜色值溢出 | 使用clamp限制 |
8.3 无障碍设计建议
♿ 无障碍设计建议 ♿
不要仅依靠颜色:使用形状、图标、文字等辅助标识
确保足够对比度:普通文本至少4.5:1
提供替代方案:高对比度模式、色盲友好主题
测试验证:使用本工具验证设计效果
九、运行说明
9.1 环境要求
| 环境 | 版本要求 |
|---|---|
| Flutter SDK | >= 3.0.0 |
| Dart SDK | >= 2.17.0 |
| 鸿蒙OS | API 21+ |
9.2 运行命令
bash
# 查看可用设备
flutter devices
# 运行到Web服务器
flutter run -d web-server -t lib/main_colorblind_simulator.dart --web-port 8110
# 运行到鸿蒙设备
flutter run -d 127.0.0.1:5555 lib/main_colorblind_simulator.dart
# 运行到Windows
flutter run -d windows -t lib/main_colorblind_simulator.dart
# 代码分析
flutter analyze lib/main_colorblind_simulator.dart
十、总结
色盲模拟器应用通过颜色矩阵转换算法,精确模拟了8种色盲类型的视觉效果,帮助设计师直观了解色盲用户的视觉体验。应用支持红色盲、绿色盲、蓝色盲、全色盲及三种色弱类型的模拟,覆盖了绝大多数色盲人群。
核心功能涵盖色盲模拟、调色板对比、对比度检测、色盲知识四大模块。色盲模拟提供实时颜色转换和UI场景示例;调色板对比展示常见颜色组合在不同色盲类型下的变化;对比度检测遵循WCAG标准,提供AAA/AA/AA Large三个等级判定;色盲知识模块科普色盲类型和无障碍设计建议。
应用采用Material Design 3设计规范,以蓝色为主色调,界面专业友好。通过本应用,希望能够帮助设计师和开发者更好地理解色盲用户的需求,设计出更加包容和无障碍的产品。
让设计对每个人都友好