# HarmonyOS ArkTS 调色板应用深度解析 —— 预设颜色 + RGB 滑块 + 实时色值显示 一、应用概述调色板Color Picker是一款实用的颜色选择工具广泛应用于设计、绘画、主题定制等场景。本项目基于 HarmonyOS ArkTS 框架实现了一个功能完善的调色板应用包含 20 种预设颜色、RGB 三通道滑块、HEX 色值实时显示以及颜色预览区域。本文将从色彩模型原理、滑块联动算法、声明式 UI 设计、HarmonyOS 特性等角度进行全面深度分析。二、架构设计2.1 整体架构┌──────────────────────────────────────────┐ │ ColorPickerView.ets │ │ (主视图组合所有子组件) │ ├──────────────────────────────────────────┤ │ ┌─────────────┐ ┌─────────────────┐ │ │ │ ColorPreview │ │ PresetGrid │ │ │ │ (颜色预览) │ │ (20 预设色块) │ │ │ └─────────────┘ └─────────────────┘ │ │ ┌──────────────────────────────────┐ │ │ │ RGBSliderGroup │ │ │ │ (R 滑块 ────●─── 255) │ │ │ │ (G 滑块 ────●─── 255) │ │ │ │ (B 滑块 ────●─── 255) │ │ │ └──────────────────────────────────┘ │ │ ┌──────────────────────────────────┐ │ │ │ HexDisplay │ │ │ │ (#FF5733) │ │ │ └──────────────────────────────────┘ │ └──────────────────────────────────────────┘2.2 数据流预设点击 / 滑块拖动 → 更新 RGB 数值 → 更新 HEX 色值 → 更新预览区域背景色 → UI 响应式重渲染三、核心技术实现3.1 颜色数据模型// ColorModel.ets export class RGBColor { red: number; // 0-255 green: number; // 0-255 blue: number; // 0-255 constructor(red: number 0, green: number 0, blue: number 0) { this.red this.clamp(red); this.green this.clamp(green); this.blue this.clamp(blue); } // 值域限定 private clamp(value: number): number { return Math.max(0, Math.min(255, Math.round(value))); } // RGB → HEX 转换 toHex(): string { const r this.red.toString(16).padStart(2, 0); const g this.green.toString(16).padStart(2, 0); const b this.blue.toString(16).padStart(2, 0); return #${r}${g}${b}.toUpperCase(); } // HEX → RGB 静态工厂 static fromHex(hex: string): RGBColor { const clean hex.replace(#, ); if (clean.length ! 6) return new RGBColor(0, 0, 0); const r parseInt(clean.substring(0, 2), 16); const g parseInt(clean.substring(2, 4), 16); const b parseInt(clean.substring(4, 6), 16); return new RGBColor(r, g, b); } // 获取 CSS 颜色字符串 toCssString(): string { return rgb(${this.red}, ${this.green}, ${this.blue}); } }3.2 预设颜色数据// PresetColors.ets export const PRESET_COLORS: RGBColor[] [ // 红色系 new RGBColor(255, 51, 51), // 亮红 new RGBColor(204, 0, 0), // 深红 new RGBColor(255, 102, 102), // 粉红 // 橙色系 new RGBColor(255, 153, 51), // 橙 new RGBColor(255, 204, 102), // 杏黄 // 黄色系 new RGBColor(255, 255, 51), // 亮黄 new RGBColor(255, 255, 204), // 乳黄 // 绿色系 new RGBColor(51, 204, 51), // 亮绿 new RGBColor(0, 153, 0), // 深绿 new RGBColor(102, 204, 102), // 草绿 // 蓝色系 new RGBColor(51, 102, 255), // 亮蓝 new RGBColor(0, 0, 204), // 深蓝 new RGBColor(102, 178, 255), // 天蓝 // 紫色系 new RGBColor(153, 51, 255), // 紫 new RGBColor(204, 153, 255), // 淡紫 // 中性色 new RGBColor(255, 255, 255), // 白 new RGBColor(204, 204, 204), // 浅灰 new RGBColor(128, 128, 128), // 中灰 new RGBColor(64, 64, 64), // 深灰 new RGBColor(0, 0, 0), // 黑 ];3.3 RGB 转 HEX 算法详解RGB 转 HEX 的本质是将十进制颜色值转换为十六进制表示RGB(255, 87, 51) → HEX(#FF5733) 转换过程 R 255 → 0xFF → FF G 87 → 0x57 → 57 B 51 → 0x33 → 33 拼接 → #FF5733十进制与十六进制的对应关系十进制十六进制十进制十六进制000128801610192C03220240F06440255FF10064转换公式十六进制字符串 decimal.toString(16).padStart(2, 0).toString(16)将数字转换为十六进制字符串.padStart(2, 0)确保输出至少两位不足前面补零3.4 完整的调色板 UI// Index.ets import { RGBColor } from ./ColorModel; import { PRESET_COLORS } from ./PresetColors; Entry Component struct Index { State currentColor: RGBColor new RGBColor(255, 87, 51); State hexDisplay: string #FF5733; build() { Column() { // 标题 Text(调色板 ) .fontSize(28) .fontWeight(FontWeight.Bold) .margin({ top: 20, bottom: 5 }) Text(选择颜色或拖动滑块调整) .fontSize(14) .fontColor(Color.Gray) .margin({ bottom: 15 }) // 1. 颜色预览区域 Column() { Text() .width(100%) .height(120) .backgroundColor(this.currentColor.toCssString()) .borderRadius(16) .shadow({ radius: 8, color: #40000000, offsetY: 4 }) } .width(90%) .padding(10) // 2. HEX 色值显示 Row() { Text(HEX) .fontSize(16) .fontWeight(FontWeight.Bold) .fontColor(Color.Gray) Text(this.hexDisplay) .fontSize(24) .fontWeight(FontWeight.Bold) .fontColor(this.currentColor.toCssString()) .margin({ left: 15 }) .fontFamily(monospace) } .width(90%) .justifyContent(FlexAlign.Start) .padding({ left: 10, top: 10, bottom: 10 }) // 3. RGB 三通道滑块 Column() { // R 通道 Row() { Text(R) .fontSize(16) .fontWeight(FontWeight.Bold) .fontColor(#FF3333) .width(30) Slider({ value: this.currentColor.red, min: 0, max: 255, step: 1 }) .width(70%) .height(40) .blockColor(#FF3333) .trackThickness(6) .onChange((value: number) { this.currentColor.red value; this.updateDisplay(); }) Text(${this.currentColor.red}) .fontSize(16) .fontWeight(FontWeight.Medium) .width(40) .textAlign(TextAlign.End) } .width(90%) .padding(5) // G 通道 Row() { Text(G) .fontSize(16) .fontWeight(FontWeight.Bold) .fontColor(#33CC33) .width(30) Slider({ value: this.currentColor.green, min: 0, max: 255, step: 1 }) .width(70%) .height(40) .blockColor(#33CC33) .trackThickness(6) .onChange((value: number) { this.currentColor.green value; this.updateDisplay(); }) Text(${this.currentColor.green}) .fontSize(16) .fontWeight(FontWeight.Medium) .width(40) .textAlign(TextAlign.End) } .width(90%) .padding(5) // B 通道 Row() { Text(B) .fontSize(16) .fontWeight(FontWeight.Bold) .fontColor(#3366FF) .width(30) Slider({ value: this.currentColor.blue, min: 0, max: 255, step: 1 }) .width(70%) .height(40) .blockColor(#3366FF) .trackThickness(6) .onChange((value: number) { this.currentColor.blue value; this.updateDisplay(); }) Text(${this.currentColor.blue}) .fontSize(16) .fontWeight(FontWeight.Medium) .width(40) .textAlign(TextAlign.End) } .width(90%) .padding(5) } .width(100%) // 分隔线 Divider() .width(90%) .margin({ top: 10, bottom: 10 }) // 4. 预设颜色网格 Text(预设颜色) .fontSize(16) .fontWeight(FontWeight.Bold) .width(90%) .margin({ bottom: 8 }) Grid() { ForEach(PRESET_COLORS, (color: RGBColor, index: number) { // 预设色块 Column() { Button() .width(44) .height(44) .backgroundColor(color.toCssString()) .borderRadius(8) .border({ width: color this.currentColor ? 3 : 1, color: color this.currentColor ? #2B6CB0 : #E2E8F0 }) .onClick(() { this.currentColor color; this.updateDisplay(); }) } .width(44) .height(44) }, (color: RGBColor) color.toHex()) } .columnsTemplate(1fr 1fr 1fr 1fr 1fr) .rowsTemplate(1fr 1fr 1fr 1fr) .width(90%) .padding(5) } .width(100%) .height(100%) .backgroundColor(#F7FAFC) .overflow(Overflow.Scroll) } // 更新显示 updateDisplay(): void { this.hexDisplay this.currentColor.toHex(); } }四、RGB 颜色模型深入4.1 色彩空间原理RGB红绿蓝是加色混色模型广泛应用于电子显示设备。其核心原理RRed红色波长 ~700nm0-255 表示从无到饱和GGreen绿色波长 ~546nm人眼最敏感的通道BBlue蓝色波长 ~435nm能量最高三个通道各 8 位0-255总计 24 位色可表示 16,777,216 种颜色。4.2 滑块联动算法当滑块拖动时需要实时更新三个数值并同步到 UI// 滑块值变化 → 更新颜色 → 刷新所有相关 UI onChange((value: number) { this.currentColor.red value; // 更新模型 this.updateDisplay(); // 触发 UI 刷新 })关键点在于State的响应式机制currentColor被State装饰修改currentColor.red后由于对象引用未变需通过方法调用触发变更检测updateDisplay()更新hexDisplay字符串该字符串是State变量触发重渲染注意ArkTS 的State是浅比较。修改对象的属性如currentColor.red value时如果对象引用不变框架可能检测不到变化。解决方案// 方案一重新赋值整个对象 this.currentColor new RGBColor(value, this.currentColor.green, this.currentColor.blue); // 方案二使用 Observed 装饰器使对象深度响应 Observed export class RGBColor { ... }4.3 颜色空间转换扩展除了 RGB ↔ HEX实际开发中可能还需要 HSV/HSL 转换// RGB → HSV 转换 function rgbToHsv(r: number, g: number, b: number): { h: number, s: number, v: number } { r / 255; g / 255; b / 255; const max Math.max(r, g, b); const min Math.min(r, g, b); const delta max - min; let h 0; if (delta ! 0) { if (max r) h ((g - b) / delta) % 6; else if (max g) h (b - r) / delta 2; else h (r - g) / delta 4; h Math.round(h * 60); if (h 0) h 360; } const s max 0 ? 0 : (delta / max) * 100; const v max * 100; return { h, s: Math.round(s), v: Math.round(v) }; }五、HarmonyOS 特性分析5.1 Slider 组件HarmonyOS 的Slider组件提供了丰富的自定义选项Slider({ value: this.currentColor.red, min: 0, max: 255, step: 1 }) .width(70%) .height(40) .blockColor(#FF3333) // 滑块按钮颜色 .trackThickness(6) // 轨道厚度 .onChange((value: number) { // 值变化回调 })Slider 关键属性min/max取值范围step步长颜色调整通常为 1blockColor滑块按钮颜色按通道区分trackThickness轨道粗细5.2 Grid 网格预设布局20 个预设颜色使用Grid组件排列为 5 列 4 行Grid() { ForEach(PRESET_COLORS, (color: RGBColor, index: number) { // 色块 }, (color: RGBColor) color.toHex()) } .columnsTemplate(1fr 1fr 1fr 1fr 1fr) // 5 列 .rowsTemplate(1fr 1fr 1fr 1fr) // 4 行5.3 响应式状态管理State currentColor当前选中的颜色驱动预览和 HEX 显示State hexDisplayHEX 字符串单独存储以便字体颜色同步5.4 阴影与圆角.shadow({ radius: 8, color: #40000000, offsetY: 4 }) .borderRadius(16)HarmonyOS 的shadowAPI 支持自定义阴影半径、颜色和偏移为 UI 添加层次感。六、UI/UX 设计6.1 交互反馈预设点击点击色块立即更新预览和滑块滑块拖动实时联动拖动滑块时颜色同步变化选中高亮当前选中预设加蓝色边框数值显示滑块右侧实时显示当前通道值6.2 视觉设计布局层次 标题 → 子标题 颜色预览区大块 HEX 色值等宽字体 RGB 滑块按通道颜色标识 —— 分隔线 —— 预设颜色5×4 网格预览区域使用大色块直观感受颜色HEX 值使用等宽字体monospace便于阅读滑块按通道着色红/绿/蓝视觉区分度高预设颜色覆盖主要色系6.3 色彩辅助功能// 颜色复制到剪贴板 function copyToClipboard(text: string): void { // HarmonyOS 剪贴板 API // pasteboard.createData(PasteType.PLAIN_TEXT, text) console.info(已复制颜色: ${text}); }七、最佳实践总结7.1 代码组织颜色模型与 UI 分离枚举预设颜色为独立模块工具函数RGB↔HEX 转换集中管理7.2 状态管理使用 Observed 装饰器实现深度响应式避免在组件内部修改 props使用单一数据源Single Source of Truth7.3 性能优化滑块 onChange 回调中避免复杂计算使用离散 stepstep1而非连续模式ForEach 使用稳定的 key颜色 HEX 值7.4 可扩展性支持 HSL/HSV 模式切换支持透明度Alpha通道支持颜色收藏和近期使用支持从图片取色八、扩展功能HSL 色相环选择器除了 RGB 滑块可以添加更直观的色相环选择器Component struct HueSlider { Prop hue: number; onChange?: (hue: number) void; build() { // 渐变轨道从红到紫跨越整个色相环 Slider({ value: this.hue, min: 0, max: 360, step: 1 }) .width(80%) .trackThickness(20) .blockColor(#FFFFFF) .onChange((value: number) { if (this.onChange) this.onChange(value); }) } }九、完整代码清单// ColorModel.ets Observed export class RGBColor { red: number; green: number; blue: number; constructor(red: number 0, green: number 0, blue: number 0) { this.red Math.max(0, Math.min(255, Math.round(red))); this.green Math.max(0, Math.min(255, Math.round(green))); this.blue Math.max(0, Math.min(255, Math.round(blue))); } toHex(): string { const r this.red.toString(16).padStart(2, 0); const g this.green.toString(16).padStart(2, 0); const b this.blue.toString(16).padStart(2, 0); return #${r}${g}${b}.toUpperCase(); } toCssString(): string { return rgb(${this.red}, ${this.green}, ${this.blue}); } }// PresetColors.ets import { RGBColor } from ./ColorModel; export const PRESET_COLORS: RGBColor[] [ new RGBColor(255, 51, 51), new RGBColor(204, 0, 0), new RGBColor(255, 102, 102), new RGBColor(255, 153, 51), new RGBColor(255, 204, 102), new RGBColor(255, 255, 51), new RGBColor(255, 255, 204), new RGBColor(51, 204, 51), new RGBColor(0, 153, 0), new RGBColor(102, 204, 102), new RGBColor(51, 102, 255), new RGBColor(0, 0, 204), new RGBColor(102, 178, 255), new RGBColor(153, 51, 255), new RGBColor(204, 153, 255), new RGBColor(255, 255, 255), new RGBColor(204, 204, 204), new RGBColor(128, 128, 128), new RGBColor(64, 64, 64), new RGBColor(0, 0, 0), ];// ColorUtils.ets import { RGBColor } from ./ColorModel; export function hexToRgb(hex: string): RGBColor { const clean hex.replace(#, ); if (clean.length ! 6) return new RGBColor(0, 0, 0); const r parseInt(clean.substring(0, 2), 16); const g parseInt(clean.substring(2, 4), 16); const b parseInt(clean.substring(4, 6), 16); return new RGBColor(r, g, b); } export function isLightColor(color: RGBColor): boolean { // 相对亮度公式 const luminance 0.299 * color.red 0.587 * color.green 0.114 * color.blue; return luminance 186; } export function getContrastTextColor(bgColor: RGBColor): string { return isLightColor(bgColor) ? #000000 : #FFFFFF; }十、总结通过本篇文章我们深入解析了 HarmonyOS 调色板应用的完整实现RGB 颜色模型—— 加色混色原理、24 位色空间RGB ↔ HEX 转换算法—— 十进制与十六进制互转滑块联动—— Slider 组件使用、三通道实时同步预设颜色选择—— 20 色覆盖主要色系、Grid 网格布局声明式 UI—— State/Observed 响应式编程、条件渲染调色板应用虽然功能看似简单但涵盖了颜色科学、UI 交互、响应式编程等多个重要领域。从颜色理论到具体实现每一步都体现了工程设计与用户体验的平衡。希望本文能为 HarmonyOS 开发者提供一个完整的技术参考。

相关新闻

最新新闻

从三极管到专用芯片:LED驱动电路方案全解析与实战设计

从三极管到专用芯片:LED驱动电路方案全解析与实战设计

1. 项目概述:从“点亮”到“驱动”的跨越刚接触电子制作的朋友,第一个项目十有八九是“点亮一颗LED”。用开发板上的GPIO口,或者一个电池加个电阻,看着小灯亮起,成就感满满。但很快你就会发现,当你想让一排…

2026/7/29 4:17:55
单片机数码管驱动原理:从静态显示到动态扫描与TM1650芯片应用

单片机数码管驱动原理:从静态显示到动态扫描与TM1650芯片应用

1. 从点亮一个“8”开始:数码管显示的本质如果你刚接触单片机,点亮第一个LED灯时的兴奋感可能还记忆犹新。那么,点亮数码管,让单片机控制它显示出清晰的数字或字母,无疑是硬件编程路上的又一个里程碑。数码管&#xff…

2026/7/29 4:17:55
DBC文件制作全攻略:从CAN总线信号解析到实战工具应用

DBC文件制作全攻略:从CAN总线信号解析到实战工具应用

1. 从零开始:DBC文件到底是什么,为什么需要它?如果你正在和汽车电子、工业控制或者机器人打交道,尤其是涉及到CAN总线通信,那么“DBC文件”这个词你肯定绕不过去。我第一次接触DBC文件时,也犯过嘀咕&#x…

2026/7/29 4:17:55
滤波电容选型实战:从理论到应用,打造稳定电源系统

滤波电容选型实战:从理论到应用,打造稳定电源系统

1. 项目概述:从“能用”到“好用”的滤波电容选型实战在电子电路设计的江湖里,滤波电容绝对算得上是一位“扫地僧”级别的存在。它看似平平无奇,规格书上无非是容量、耐压、尺寸、材质,但真正用起来,选对了是“润物细无…

2026/7/29 4:17:55
等保2.0下交换机安全配置:5大高频漏洞加固与实战指南

等保2.0下交换机安全配置:5大高频漏洞加固与实战指南

1. 项目概述:为什么交换机安全配置是等保2.0的“咽喉要道”干了这么多年网络运维和安全合规,我越来越觉得,交换机这玩意儿,就像家里的总电闸。平时没人注意它,一旦出问题,整个网络都得“停电”。尤其是在等…

2026/7/29 4:17:55
从LED驱动到MCU控制:一个硬件工程师的汽车尾灯模组实战设计全解析

从LED驱动到MCU控制:一个硬件工程师的汽车尾灯模组实战设计全解析

1. 项目概述:从“尾灯模组”说起,一个硬件工程师的实战拆解“尾灯模组”这四个字,在汽车电子、消费电子乃至创客圈里,都是一个既经典又充满挑战的课题。乍一看,它不就是让几个LED亮起来、灭下去,再搞点流水…

2026/7/29 4:12:54

月新闻