在 SF Symbols 中使用可变颜色
Adopt Variable Color in SF Symbols
2022年6月6日
一句话判断
SF Symbols 4 带来的 Variable Color 功能让图标能根据一个百分比值动态改变渲染状态——Wi-Fi 信号强度、电池电量这类场景再也不用自己拼多套图标了。
这场 Session 讲了什么
苹果在 SF Symbols 4 中引入了 Variable Color(可变颜色)特性。在此之前,很多图标(比如 Wi-Fi 信号、蜂窝信号、扬声器音量)需要开发者准备多套不同状态的图片资源来表示不同的级别。Variable Color 让你只需要一个符号,通过传入一个 0 到 1 之间的百分比值来控制图标的渲染状态。
比如 Wi-Fi 符号,传入 0.5 就只显示一半的信号条;扬声器符号,传入 0.75 就显示三格音量。这个百分比不仅控制图标的可见层数,还控制颜色的渲染方式。
Session 还介绍了 SF Symbols 的统一标注工作流(unified annotation workflow)和新的 template format 4.0。自定义符号现在可以同时支持多种渲染模式(单色、多色、分层、调色板),而不需要为每种模式创建单独的模板。
值得深挖的点
Variable Color 和 Rendering Mode 的配合。 可变颜色不是独立工作的,它和 SF Symbols 的四种渲染模式(monochrome, multicolor, hierarchical, palette)紧密配合。在 hierarchical 模式下,可变颜色的层级会自动获得不同的灰度处理;在 palette 模式下,你可以精确控制每一层用什么颜色。这意味着同一个符号,在不同的渲染模式下可以呈现完全不同的视觉效果。
Template Format 4.0 是一个隐藏的大更新。 之前自定义 SF Symbol 需要为每种渲染模式导出不同的 SVG 文件。Format 4.0 允许在一个文件中通过标注(annotation)同时定义所有渲染模式的行为。这对自定义图标库的维护成本来说是巨大的降低。
代码片段
// 使用 Variable Color 渲染 Wi-Fi 信号强度
let wifiSymbolName = "wifi"
// 方式一:使用 UIImage 的 variableValue
let wifiImage = UIImage(systemName: wifiSymbolName)?
.withVariableValue(0.6) // 60% 信号强度
// 方式二:在 SwiftUI 中使用
struct SignalStrengthView: View {
let signalLevel: Double // 0.0 到 1.0
var body: some View {
Image(systemName: "wifi")
.symbolVariableValue(signalLevel)
.symbolRenderingMode(.hierarchical)
.font(.title)
}
}
// 电池图标的动态显示
struct BatteryView: View {
let batteryLevel: Double
var body: some View {
Image(systemName: "battery.100")
.symbolVariableValue(batteryLevel)
.symbolRenderingMode(.palette)
.foregroundStyle(.green, .white)
}
}
最佳实践
- 检查符号是否支持 Variable Color——不是所有 SF Symbol 都有可变颜色层级。可以在 SF Symbols App 中查看每个符号支持的特性。
- 使用
symbolRenderingMode()来匹配你的设计系统,不同渲染模式下的可变颜色效果差异很大。 - 自定义符号时使用 Template Format 4.0,避免为每种渲染模式创建单独的文件。
- 动画过渡时使用
withAnimation,可变颜色的变化会自动获得平滑的插值动画。
还有什么值得关注
- SF Symbols App 现在可以实时预览 Variable Color 的效果,拖动滑块就能看到不同百分比下的渲染结果。
- 支持 Variable Color 的符号有一个特殊的标注系统,导出自定义符号时需要注意保留这些标注。
symbolVariableValue是 SwiftUI 专属 API,UIKit 使用UIImage.withVariableValue()。- 苹果推荐在表示”进度”或”级别”的场景中使用 Variable Color,而不是用它来做普通的颜色动画。