关于 axiom-sf-symbols
面向 SwiftUI 开发者的 SF Symbols 使用指南,涵盖渲染模式、符号效果和自定义符号制作。还介绍 SF Symbols 7 的 Draw 动画、效果选择及无障碍相关注意事项。
主要功能
- 01四种符号渲染模式
- 02离散与持续符号效果
- 03过渡和内容替换效果
- 04SF Symbols 7 Draw 动画
- 05自定义符号制作与无障碍
适用场景
- 01为图标选择渲染模式
- 02为按钮或加载状态添加动画
- 03排查符号颜色和效果问题
- 04制作支持 Draw 动画的自定义符号
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ charleswiltgen/ axiom --skill axiom-sf-symbols安装后在 Claude Code 中输入/axiom-sf-symbols确认已加载。
详细介绍
SF Symbols — 效果、渲染与自定义符号
何时使用此技能
适用于:
- 在渲染模式(Monochrome、Hierarchical、Palette、Multicolor)之间进行选择
- 实现符号效果或动画(Bounce、Pulse、Scale、Wiggle、Rotate、Breathe、Draw)
- 使用 SF Symbols 7 的 Draw On/Off 动画
- 在 SF Symbols 应用中创建自定义符号
- 排查符号颜色、效果未播放或字重不匹配的问题
- 确定哪种效果适合特定的 UX 目的
- 处理符号动画的辅助功能(Reduce Motion)
相关技能
- 使用
axiom-sf-symbols-ref获取完整的 API 参考,包括所有修饰符、UIKit 对应项和平台可用性矩阵 - 使用
axiom-swiftui-animation-ref获取通用 SwiftUI 动画参考(非符号专用) - 使用
axiom-hig-ref获取更广泛的图标设计指南
示例提示词
1. “我的 SF Symbol 显示为单一纯色,但我想让它通过多种色调呈现层次感。该如何解决?”
此技能介绍如何选择渲染模式:使用 Hierarchical 通过单一颜色呈现层次感,使用 Palette 为各图层指定颜色
2. “我想让下载按钮在点按时播放动画,下载过程中显示旋转指示器,完成后再动画变成勾号。”
此技能介绍效果选择:使用 Bounce 提供点按反馈,使用 Breathe/Pulse 表示进行中,使用 Replace 配合内容过渡效果表示完成
3. “我尝试使用 SF Symbols 7 中新增的 Draw 动画,但效果没有播放。”
此技能介绍 Draw On/Off 的实现、播放模式、iOS 26 要求和常见故障排查方法
4. “如何创建支持所有渲染模式和新增 Draw 动画的自定义符号?”
此技能介绍自定义符号的创作流程、模板图层,以及使用引导点进行 Draw 标注
第 1 部分:渲染模式决策树
SF Symbols 支持 4 种渲染模式。正确的选择取决于你的设计意图。
快速决策
Need depth from ONE color? → Hierarchical
Need specific colors per layer? → Palette
Want Apple's curated colors? → Multicolor
Just need a tinted icon? → Monochrome (default)
Monochrome
默认模式。所有图层都使用相同的颜色(你的 foregroundStyle)进行渲染。
Image(systemName: "cloud.rain.fill")
.foregroundStyle(.blue)
// All layers are blue
适用场景:简单的着色图标、与文本颜色匹配的图标、工具栏项目、标签栏项目。
Hierarchical
使用从单一颜色派生的不同不透明度渲染各图层。主要图层完全不透明;次要和第三级图层的透明度依次增加。无需指定多种颜色即可呈现层次感。
Image(systemName: "cloud.rain.fill")
.symbolRenderingMode(.hierarchical)
.foregroundStyle(.blue)
// Cloud is full blue, rain drops are lighter blue
适用场景:希望呈现视觉层次感,同时保持图标与单一色调协调一致时。这是制作精致 UI 时最常见的选择。
Palette
为每个图层指定明确的颜色。与 Hierarchical 不同,它不会自动派生不透明度,你可以直接控制每个图层的颜色。
Image(systemName: "cloud.rain.fill")
.symbolRenderingMode(.palette)
.foregroundStyle(.blue, .cyan)
// Cloud is blue, rain drops are cyan
适用场景:品牌图标、颜色具有特定含义的状态指示器,以及需要精确控制颜色的设计。
注意事项:如果提供的颜色数量少于图层数量,多出的图层会重复使用最后一种颜色。如果符号有 3 个图层,而你只提供 2 种颜色,那么第三个图层会使用第二种颜色。
Multicolor
使用 Apple 为每个符号预先定义的配色方案。颜色固定,无法自定义。
Image(systemName: "cloud.rain.fill")
.symbolRenderingMode(.multicolor)
// Cloud is white, rain drops are blue (Apple's design)
适用场景:天气指示器、文件类型图标,或任何适合采用 Apple 精心设计方案的场合。并非所有符号都支持 Multicolor;不支持的符号会回退到 Monochrome。
常见错误
| 错误 | 影响 | 修正方法 |
|---|---|---|
在 Multicolor 模式下使用 .foregroundColor() | 覆盖 Apple 的颜色 | 移除前景色修饰符 |
| 使用 Palette 时只设置 1 种颜色 | 外观与 Monochrome 相同 | 为每个图层提供颜色 |
| 假设所有符号都支持 Multicolor | 回退到 Monochrome | 先在 SF Symbols 应用中检查 |
| 图层需要表达不同含义时仍使用 Hierarchical | 颜色无法传达语义 | 改用 Palette |
第 2 部分:符号效果系统
符号效果让 SF Symbols 通过动态效果焕发生机。每种效果都属于四种行为类别之一。
效果类别
| 类别 | 触发条件 | 持续时间 | 使用场景 |
|---|---|---|---|
| 离散 | 值发生变化 | 单次 | 点击反馈、事件通知 |
| 无限 | isActive 布尔值 | 持续运行,直到停止 | 加载状态、持续进行的流程 |
| 过渡 | 视图插入或移除 | 单次 | 按指定样式显示或消失 |
| 内容过渡 | 符号切换 | 单次 | 将一个符号替换为另一个符号 |
不同 UX 目的对应的效果
User tapped something → Bounce (discrete)
Something changed, draw attention → Wiggle (discrete, iOS 18+)
Ongoing process/loading → Pulse, Breathe, or Variable Color (indefinite)
Rotation indicates progress → Rotate (indefinite, iOS 18+)
Show/hide symbol → Appear/Disappear (transition)
Swap between two symbols → Replace (content transition)
Symbol enters with hand-drawn style → Draw On (iOS 26+)
Symbol exits with hand-drawn style → Draw Off (iOS 26+)
Progress indicator along path → Variable Draw (iOS 26+)
Scale up/down for emphasis → Scale (indefinite)
离散效果
值发生变化时触发一次。符号执行动画后恢复静止状态。
弹跳
最常见的离散效果。短暂而富有弹性的动画。
@State private var downloadCount = 0
Image(systemName: "arrow.down.circle")
.symbolEffect(.bounce, value: downloadCount)
每次 downloadCount 发生变化时,都会触发动画。
方向选项:.bounce.up、.bounce.down
摇摆(iOS 18+)
水平摇晃,以引起对符号的注意。
Image(systemName: "bell.fill")
.symbolEffect(.wiggle, value: notificationCount)
方向选项:.wiggle.left、.wiggle.right、.wiggle.forward、.wiggle.backward
.forward 和 .backward 会遵循阅读方向,适用于支持 RTL 的场景。
旋转(作为离散效果,iOS 18+)
值变化触发时,旋转一次。
Image(systemName: "arrow.trianglehead.2.clockwise")
.symbolEffect(.rotate, value: refreshCount)
选项:.rotate.clockwise、.rotate.counterClockwise
按图层旋转:某些符号只旋转特定图层(例如,风扇叶片旋转,但外壳保持不动)。使用 .rotate.byLayer 可启用此效果。
无限效果
当 isActive 为 true 时持续运行。当 isActive 变为 false 时停止。
脉冲
轻微的透明度脉冲效果,适用于“等待”状态。
Image(systemName: "network")
.symbolEffect(.pulse, isActive: isConnecting)
可变颜色
依次突出显示符号的各个图层,营造“逐渐填充”或“循环变化”的效果。
Image(systemName: "wifi")
.symbolEffect(.variableColor.iterative, isActive: isSearching)
变体:
.variableColor.iterative— 一次突出显示一个图层.variableColor.cumulative— 逐步填充图层.variableColor.reversing— 来回循环- 组合使用:
.variableColor.iterative.reversing
缩放
放大或缩小符号。
Image(systemName: "mic.fill")
.symbolEffect(.scale.up, isActive: isRecording)
呼吸(iOS 18+)
平滑、有节奏的缩放动画,让符号看起来像在呼吸。
Image(systemName: "heart.fill")
.symbolEffect(.breathe, isActive: isMonitoring)
变体:.breathe.plain(仅缩放)、.breathe.pulse(缩放 + 透明度)
旋转(作为无限效果,iOS 18+)
持续旋转,适用于处理状态指示器。
Image(systemName: "gear")
.symbolEffect(.rotate, isActive: isProcessing)
效果选项
所有效果都可通过 options 参数接受 SymbolEffectOptions。
// Repeat 3 times
.symbolEffect(.bounce, options: .repeat(3), value: count)
// Double speed
.symbolEffect(.pulse, options: .speed(2.0), isActive: true)
// Repeat continuously
.symbolEffect(.variableColor, options: .repeat(.continuous), isActive: true)
// Non-repeating (run once)
.symbolEffect(.breathe, options: .nonRepeating, isActive: true)
// Combine options
.symbolEffect(.bounce, options: .repeat(5).speed(1.5), value: count)
过渡效果
用于基于符号的视图在视图层级中出现或消失时。
if showSymbol {
Image(systemName: "checkmark.circle.fill")
.transition(.symbolEffect(.appear))
}
可用过渡效果:.appear、.disappear
变体:.appear.up、.appear.down、.disappear.up、.disappear.down
内容过渡
用于为符号之间的切换添加动画。应用于容器,而非符号本身。
@State private var isFavorite = false
Button {
isFavorite.toggle()
} label: {
Image(systemName: isFavorite ? "star.fill" : "star")
.contentTransition(.symbolEffect(.replace))
}
替换变体:
.replace.downUp— 旧符号向下移动,新符号向上移动.replace.upUp— 两个符号都向上移动.replace.offUp— 旧符号淡出,新符号向上移动
魔法替换
当两个符号具有相同的结构(例如 star 和 star.fill,或 pause.fill 和 play.fill)时,Replace 会自动执行魔法替换:过渡时变形共享元素,同时过渡不同部分。在 iOS 18+ 中,.replace 的默认行为就是魔法替换。若要显式控制:
// Explicit Magic Replace with fallback
.contentTransition(.symbolEffect(.replace.magic(fallback: .replace.downUp)))
第 3 部分:SF Symbols 7 — 绘制动画(iOS 26+)
绘制动画模拟用笔绘制符号时的自然过程。这是 SF Symbols 7 的标志性新功能。
绘制出现和绘制消失
绘制出现会逐笔“绘制”符号,使其显示出来。 绘制消失会通过“擦除”符号,使其消失。
// Draw On — symbol draws in when isComplete becomes true
Image(systemName: "checkmark.circle")
.symbolEffect(.drawOn, isActive: isComplete)
// Draw Off — symbol draws out when isHidden becomes true
Image(systemName: "star.fill")
.symbolEffect(.drawOff, isActive: isHidden)
播放模式
控制多层符号的绘制动画方式:
// By Layer (default) — staggered timing, layers overlap
Image(systemName: "square.and.arrow.up")
.symbolEffect(.drawOn.byLayer, isActive: showIcon)
// Whole Symbol — all layers draw simultaneously
Image(systemName: "square.and.arrow.up")
.symbolEffect(.drawOn.wholeSymbol, isActive: showIcon)
// Individually — sequential, each layer completes before next starts
Image(systemName: "square.and.arrow.up")
.symbolEffect(.drawOn.individually, isActive: showIcon)
各模式的适用场景:
- 按图层(默认):感觉最自然,适用于大多数符号
- 整个符号:适用于符号应作为一个整体出现,而不是分部分出现的情况
- 分别播放:适用于需要分别突出显示每个图层的情况(讲故事、引导入门)
绘制关闭方向
绘制关闭支持控制动画正向还是反向播放:
// Forward (default) — follows the draw path
.symbolEffect(.drawOff.nonReversed, isActive: isHidden)
// Reversed — erases in reverse order of how it was drawn
.symbolEffect(.drawOff.reversed, isActive: isErasing)
可变绘制
可变绘制使用 SymbolVariableValueMode.draw,根据 0.0 到 1.0 的数值部分绘制符号的笔画路径,非常适合进度指示器。
Image(systemName: "thermometer.high", variableValue: temperature)
.symbolVariableValueMode(.draw) // iOS 26+
与传统的可变颜色(为每个图层设置不透明度)对比:
Image(systemName: "wifi", variableValue: signalStrength)
.symbolVariableValueMode(.color) // iOS 17+ (default behavior)
限制:一个符号可以同时支持可变颜色和可变绘制,但渲染时只能启用一种模式。设置不受支持的模式不会产生可见效果。
渐变渲染
SF Symbols 7 引入了 SymbolColorRenderingMode,可使用单一源颜色生成渐变填充。
Image(systemName: "star.fill")
.symbolColorRenderingMode(.gradient) // iOS 26+
.foregroundStyle(.red)
| 模式 | 描述 |
|---|---|
.flat | 纯色填充(默认) |
.gradient | 从源颜色生成的轴向渐变 |
渐变适用于所有渲染模式,在较大尺寸下效果最佳。
使用绘制效果实现魔法替换
在某些符号对之间使用 .contentTransition(.symbolEffect(.replace)) 时,系统现在会将退出符号的绘制关闭与进入符号的绘制开启结合起来。如果有共用的外框(例如圆形轮廓),则会保留该外框,同时让内部元素通过绘制动画进行过渡。
// Automatic Draw-enhanced Magic Replace
Image(systemName: isComplete ? "checkmark.circle.fill" : "circle")
.contentTransition(.symbolEffect(.replace))
自定义符号绘制注释
若要在自定义符号上启用绘制动画,请在 SF Symbols 应用中为路径添加注释:
- 打开 SF Symbols 7 中的自定义符号
- 选择一个路径图层
- 添加引导点以定义绘制方向:
- 起点(空心圆):绘制开始的位置
- 终点(实心圆):绘制结束的位置
- 转角点(菱形):方向发生急剧变化的位置
- 双向点:启用从中心向外绘制
- 附着点:连接不参与绘制的装饰元素
- 最低要求:每条路径至少有两个引导点(起点和终点)
- 使用 SF Symbols 应用中的预览面板进行测试
按住 Option 并拖动引导点,可精确调整位置。使用上下文菜单配置方向和端帽。
第 4 部分:反模式
错误的渲染模式
| 模式 | 问题 | 修正方法 |
|---|---|---|
| 使用 1 种颜色的调色板 | 等同于单色模式,浪费 API 调用 | 使用单色模式或提供多种颜色 |
| 为品牌图标使用多色模式 | 无法自定义 Apple 固定的颜色 | 使用包含品牌颜色的调色板 |
硬编码 .foregroundColor(.blue) | 忽略深色模式、动态字体和辅助功能 | 使用带语义颜色的 .foregroundStyle() |
| 为状态指示器使用分层模式 | 图层不具备不同含义 | 使用带语义颜色的调色板 |
错误的效果选择
| 模式 | 问题 | 修正方法 |
|---|---|---|
| 为加载状态使用弹跳 | 仅播放一次,无法传达“持续进行中” | 使用脉冲、呼吸或可变颜色 |
| 为轻点反馈使用脉冲 | 效果太弱,无法确认操作 | 使用弹跳 |
| 为非机械符号使用连续旋转 | 用于有机形状时显得不自然 | 为有机符号使用呼吸效果 |
| 为短暂状态变化使用绘制开启 | 对频繁切换来说过于夸张 | 使用替换或缩放 |
缺少 iOS 版本检查
// ❌ Crashes on iOS 17
Image(systemName: "bell")
.symbolEffect(.wiggle, value: count) // Wiggle requires iOS 18+
// ✅ Safe version check
Image(systemName: "bell")
.modifier(BellEffectModifier(count: count))
struct BellEffectModifier: ViewModifier {
let count: Int
func body(content: Content) -> some View {
if #available(iOS 18, *) {
content.symbolEffect(.wiggle, value: count)
} else {
content.symbolEffect(.bounce, value: count)
}
}
}
忽略减少动态效果设置
符号效果会自动遵循辅助功能中的减少动态效果设置,大多数效果会被抑制或简化。但是,如果你使用效果来传达关键信息(而非仅作装饰),请提供替代方案:
// Variable Color conveys WiFi strength — provide text fallback
Image(systemName: "wifi")
.symbolEffect(.variableColor, isActive: isSearching)
.accessibilityLabel("Searching for WiFi networks")
不要关闭减少动态效果设置,也不要尝试强制播放效果。系统对此的处理是正确的。
缺少无障碍标签
// ❌ VoiceOver says "star.fill"
Image(systemName: "star.fill")
// ✅ VoiceOver says "Favorite"
Image(systemName: "star.fill")
.accessibilityLabel("Favorite")
使用 .contentTransition(.symbolEffect(.replace)) 替换符号时,请更新无障碍标签,使其与当前状态匹配:
Image(systemName: isFavorite ? "star.fill" : "star")
.contentTransition(.symbolEffect(.replace))
.accessibilityLabel(isFavorite ? "Remove from favorites" : "Add to favorites")
第 5 部分:故障排除
效果未播放
症状:已应用 .symbolEffect() 修饰符,但看不到动画。
- 检查 iOS 版本 — Bounce/Pulse/Scale 需要 iOS 17+,Wiggle/Rotate/Breathe 需要 iOS 18+,Draw 需要 iOS 26+
- 检查减少动态效果 — 设置 > 辅助功能 > 动态效果 > 减少动态效果。开启后,大多数效果会被抑制
- 检查触发类型 — 离散效果需要发生变化的
value:。持续效果需要isActive: true。过渡效果需要视图实际进入或离开视图层级 - 检查符号兼容性 — 并非所有符号都支持所有效果。打开 SF Symbols 应用,选择符号,然后检查 Animation 检查器
- 检查是否存在冲突效果 — 同一视图上的多个
.symbolEffect()修饰符可能会冲突。请使用单个效果,或通过选项组合效果
渲染模式下颜色不正确
症状:符号颜色与预期外观不符。
- 检查渲染模式 — 如果设置了
.foregroundStyle,但只看到一种颜色,可能需要.symbolRenderingMode(.palette)或.hierarchical - 检查
.tint与.foregroundStyle— 在 UIKit 中,tintColor会影响 Monochrome 和 Hierarchical。对于 Palette,请使用UIImage.SymbolConfiguration(paletteColors:) - 检查 Multicolor 支持 — 并非所有符号都有 Multicolor 变体。不支持的符号会回退到 Monochrome
- 检查环境 — 父视图中的
.foregroundStyle可能会覆盖你的渲染模式。请直接在 Image 上应用.symbolRenderingMode()
自定义符号字重不匹配
症状:自定义符号与文本或其他符号放在一起时显得太细或太粗。
- 检查模板字重 — 自定义符号需要与 9 种 SF Pro 字重匹配的字重变体。通过 SF Symbols 应用导出时会处理这一点
- 检查
.font()对齐 — 符号的字重遵循应用的字体字重。如果使用.font(.title),请确保自定义符号具有合适的字重变体 - 检查缩放 —
.imageScale(.small/.medium/.large)会影响整体大小。请使用.font()匹配字重
自定义符号的 Draw 动画不起作用
症状:自定义符号应用了 .symbolEffect(.drawOn),但没有播放绘制动画。
- 检查引导点 — 自定义符号需要添加 Draw 注释,每条路径至少包含 2 个引导点(起点 + 终点)
- 检查 SF Symbols 应用版本 — Draw 注释需要 SF Symbols 7+
- 检查路径结构 — 引导点必须放置在描边路径上,而不是填充区域上。需要绘制动画的地方,请将填充区域转换为描边
- 检查图层结构 — 每个可添加注释的图层都需要自己的引导点
第 6 部分:压力场景
场景 1:“直接用静态图片就行,符号没必要”
背景:设计师提供了 PNG 图标。开发者考虑用它们替代 SF Symbols。
重要原因:静态 PNG 无法适配动态字体、粗体文本、深色模式或无障碍设置,也不支持符号效果。
专业回应:“SF Symbols 会随文本缩放,支持 9 种字重,能自动适配深色模式和粗体文本,还无需自定义代码即可实现动画。PNG 则需要 @1x/@2x/@3x 变体、手动处理深色模式、手动缩放以适配动态字体,以及自定义动画代码。花 10 分钟找到合适的 SF Symbol,可以省下数小时的资源管理时间。”
跳过的时间成本:管理资源需 2–4 小时,外加持续维护;而找到合适的符号只需 10 分钟。
场景 2:“动画以后再加”
背景:冲刺周期即将结束。PM 认为动画只是锦上添花,可以稍后再做。
原因:事后补加符号效果需要重构状态管理。由 value: 变化触发的效果需要从一开始就采用合适的状态架构。
专业回应:“添加 .symbolEffect(.bounce, value: count) 只需一行。之后再重构状态以支持它,就得进行重构。我现在就加上这个效果——真的只需添加一个修饰符。”
场景 3:“绘制动画在我们的自定义符号上看起来很别扭”
背景:自定义符号的绘制动画效果不佳——路径的绘制顺序或方向出乎意料。
原因:绘制注释需要有意放置引导点。没有引导点时,系统只能猜测,而且经常猜错。
修复方法:在 SF Symbols 7 应用中打开自定义符号,为每条路径明确定义起点、终点和方向,并添加引导点。测试每种字重变体。请参阅上文的“自定义符号绘制注释”部分。
资源
WWDC:2023-10257、2023-10258、2024-10188、2025-337
文档:/symbols、/symbols/symboleffect、/symbols/symbolrenderingmode、/swiftui/image/symboleffect(:options:value:)、/swiftui/image/symbolrenderingmode(:)
技能:axiom-sf-symbols-ref、axiom-hig-ref、axiom-swiftui-animation-ref
最后更新:基于 WWDC 2023/10257-10258、WWDC 2024/10188、WWDC 2025/337 版本:iOS 17+(效果)、iOS 18+(Wiggle/Rotate/Breathe)、iOS 26+(Draw On/Off、Variable Draw、Gradients)