第40篇|美颜预设:自然、人像、清透如何变成可解释选项
第40篇|美颜预设:自然、人像、清透如何变成可解释选项
相机 App 的效果设置很容易做成一堆参数开关,但训练营项目选择了更贴近用户理解的表达:自然、人像、清透。它们不直接暴露底层算法参数,而是作为拍摄语义进入页面状态、拍摄摘要和后续记录。
这一篇我们不讨论美颜算法本身,而是看工程上如何把“可理解的预设”变成稳定的状态管理。对于智能相机,用户不一定关心每个参数值,但他需要知道当前拍出来的照片用了什么风格。
这一篇继续围绕 21 天「智能相机开发实战」训练营展开。内容只使用当前项目里的 ArkTS、服务层代码和真实页面截图来讲,不把封面图放进正文。阅读时可以先看截图理解用户侧效果,再顺着函数名回到工程定位实现。
本篇目标
- 把美颜预设设计成稳定枚举,而不是散落字符串。
- 理解选项数组、选中态和标签推导之间的关系。
- 掌握效果面板如何复用 chip 组件。
- 让拍摄摘要记录用户选择,避免效果不可追踪。
对应源码位置
entry/src/main/ets/pages/Index.ets
一、效果选项要先有产品语义
BeautyPresetKey只有三个值:natural、portrait、clear。这比直接出现“磨皮 30、提亮 20、锐化 10”更适合训练营项目,因为文章、截图和实际体验都能围绕用户能理解的词展开。
当选项变成类型以后,后续 UI、摘要和记录都可以引用同一组 key。这样改文案不会影响业务判断,改状态也不需要全文搜索中文标签。
图1 相机页中的美颜预设入口和用户可感知效果设置
二、枚举和状态集中定义,避免魔法字符串
项目把效果分类、美颜预设、补光颜色和水印样式都放在页面顶部的类型定义和状态区域。你可以一眼看出拍摄效果有哪些维度,也能知道当前默认值是什么。
这种写法适合训练营讲解:学员先从状态看功能边界,再进入 UI 和拍摄链路,不会被分散在多个 Builder 里的字符串干扰。
图2 拍摄效果的枚举、状态和选项数组集中定义
type BeautyPresetKey = 'natural' | 'portrait' | 'clear'; type FillLightColorKey = 'off' | 'warm' | 'cool' | 'rose'; type WatermarkStyleKey = 'none' | 'time' | 'place' | 'dual'; type CameraEffectCategoryKey = 'beauty' | 'fillLight' | 'watermark'; type PhotoOutputReadyKey = 'dualBack' | 'dualFront' | 'single'; interface MemoryRecordGroup { key: string; latitude: number; longitude: number;这里建议继续保持 key 的稳定性。后续如果要接入真正的图像效果参数,可以在 key 到参数表之间新增映射,而不是直接改掉 key。
三、标签和摘要从状态推导
getBeautyPresetLabel把内部 key 转成用户能看懂的中文标签。拍摄摘要再把美颜、补光、水印拼成一句简短说明。这样用户拍完以后知道“这张照片为什么看起来这样”,记录回看时也能知道当时的拍摄设置。
摘要不是装饰文案,它承担了轻量审计作用。以后做云同步、分享或导出时,摘要可以成为照片元信息的一部分。
图3 美颜标签和拍摄摘要由当前状态推导
private getBeautyPresetLabel(preset: BeautyPresetKey): string { if (preset === 'portrait') { return '人像'; } if (preset === 'clear') { return '清透'; } return '自然'; } private getBeautyOverlayColor(): string { if (this.selectedBeautyPreset === 'portrait') { return '#22FFD3C2'; } if (this.selectedBeautyPreset === 'clear') { return '#1EDDF8FF'; } return '#0DFFFFFF'; } private getBeautyOverlayOpacity(): number { if (this.selectedBeautyPreset === 'portrait') { return 0.54; } if (this.selectedBeautyPreset === 'clear') { return 0.42; } return 0.22; }把标签推导封装成函数还有一个好处:UI 多处展示同一个预设时,不会出现一个地方叫“清透”、另一个地方叫“通透”的不一致。
四、效果面板复用同一个 Chip 组件
效果面板根据当前分类渲染对应选项。美颜、补光、水印看起来是三组不同功能,但它们在交互上都是“点选一个 chip,更新状态,刷新选中态”。因此项目用buildCameraEffectChip复用样式和点击行为。
如果每一组效果都手写按钮,很快会出现圆角、字体、背景和点击逻辑不一致。训练营项目更适合把这类重复 UI 收口,让文章可以把重点放在状态流上。
图4 buildCameraEffectSelectedOptions 渲染美颜、补光、水印选项
private buildCameraEffectSelectedOptions() { Scroll() { Row({ space: 8 }) { if (this.selectedCameraEffectCategory === 'beauty') { ForEach(this.beautyPresetOptions, (preset: BeautyPresetKey) => { this.buildCameraEffectChip(this.getBeautyPresetLabel(preset), this.selectedBeautyPreset === preset, () => { this.selectedBeautyPreset = preset; this.cameraEffectOptionRevision += 1; this.lastCaptureSummary = this.getCameraEffectSummary(); }) }, (preset: BeautyPresetKey) => `${preset}-${this.selectedBeautyPreset}-${this.cameraEffectOptionRevision}`) } else if (this.selectedCameraEffectCategory === 'fillLight') { ForEach(this.fillLightColorOptions, (color: FillLightColorKey) => { this.buildCameraEffectChip(this.getFillLightLabel(color), this.selectedFillLightColor === color, () => { this.selectedFillLightColor = color; this.cameraEffectOptionRevision += 1; this.lastCaptureSummary = this.getCameraEffectSummary(); }) }, (color: FillLightColorKey) => `${color}-${this.selectedFillLightColor}-${this.cameraEffectOptionRevision}`) } else { ForEach(this.watermarkStyleOptions, (style: WatermarkStyleKey) => { this.buildCameraEffectChip(this.getWatermarkStyleLabel(style), this.selectedWatermarkStyle === style, () => { this.selectedWatermarkStyle = style; this.cameraEffectOptionRevision += 1; this.lastCaptureSummary = this.getCameraEffectSummary(); }) }, (style: WatermarkStyleKey) => `${style}-${this.selectedWatermarkStyle}-${this.cameraEffectOptionRevision}`) } }这一段代码也说明了一个 ArkUI 实战习惯:列表 key 要包含当前选中状态或修订号,避免选项变化后 UI 复用造成显示不刷新。
工程检查清单
- 预设 key 使用英文稳定值,展示文案通过函数转换。
- 默认值在状态区清晰可见,方便排查首次进入页面的效果。
- 拍摄摘要要包含用户选择过的效果信息。
- 效果面板复用 chip 组件,减少 UI 分叉。
- 新增效果时先扩展类型和选项数组,再补标签和摘要。
今日练习
- 新增一个
cinematic美颜 key,先不实现算法,只让 UI 能显示并进入摘要。 - 检查效果面板切换分类时,之前选中的美颜状态是否仍然保留。
- 思考如果以后接入真实美颜 SDK,key 到参数表应该放在页面层还是服务层。
训练营后面的内容会继续按“真实页面效果 → 源码定位 → 状态闭环 → 可验证结果”的节奏推进。每一篇都尽量让你能拿着代码直接回到项目里复现,而不是只停留在概念说明。
