SF Symbols 动画完全指南
目录
- SF Symbols 动画概览
- 七种动画效果详解
- UIKit / Objective-C 实战
- 创建自定义动画符号
- 符号组件(Symbol Components)
- 兼容性与导出
- 最佳实践
- SF Symbols 7 新特性(WWDC 2025)
1. SF Symbols 动画概览
SF Symbols 5(随 iOS 17 / macOS Sonoma 推出)引入了一套完整的符号动画体系。相比之前静态的图像切换,新的动画 API 让符号本身"活"了起来——弹跳、脉冲、出现/消失、渐变替换,每种效果都由苹果精心调校,开发者无需手写关键帧动画
当然如果你想的话也可以在SF Symbol中自定义动画,然后导入到项目中
三大框架均支持:
| 框架 | 主要 API |
|---|---|
| UIKit | addSymbolEffect: / setSymbolImage:contentTransition: |
| AppKit | addSymbolEffect: / setSymbolImage:contentTransition: |
| SwiftUI | .symbolEffect() 修饰符 |
本文以 UIKit + Objective-C 为主
2. 七种动画效果详解
由于使用英文可以更好的表示意思,并且可以在代码中体现的清晰一些,这里主要使用英文来做主名字
SF Symbols 5 提供 7 种预设动画,按"行为类型"分为四类:
| 效果 | 行为类型 | 说明 |
|---|---|---|
| Bounce(弹跳) | 离散 | 触发后播放一次弹跳 |
| Pulse(脉冲) | 离散 / 无限 | 符号图层透明度脉动闪烁 |
| Variable Color(可变颜色) | 离散 / 无限 | 按图层顺序渐次点亮颜色 |
| Scale(缩放) | 无限 | 持续放大或缩小 |
| Appear(出现) | 过渡 / 无限 | 符号淡入 |
| Disappear(消失) | 过渡 / 无限 | 符号淡出 |
| Replace(替换) | 内容过渡 | 从一个符号动画切换到另一个 |
行为类型说明
- 离散(Discrete):动画播放一次后自动结束,适合响应按钮点击等事件。
- 无限(Indefinite):持续播放直到手动移除,适合表示"进行中"的状态。
- 过渡(Transition):视图进入或离开层级时触发,分为两个空间(见第 3 节)。
- 内容过渡(Content Transition):在同一 ImageView 中将符号 A 平滑切换为符号 B。
3. UIKit / Objective-C 实战
3.1 无限效果 —— Variable Color(可变颜色)
适合"正在连接 Wi-Fi""正在加载"等持续状态。
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"wifi.router"]];
// 添加可变颜色动画(迭代 + 反向)
[imageView addSymbolEffect:[NSSymbolVariableColorEffect effect].iterative.reversing];
// 同时叠加缩放效果
[imageView addSymbolEffect:[NSSymbolScaleEffect effectScalingUp]];
移除无限效果:
// 按类型移除
[imageView removeSymbolEffectOfType:[NSSymbolVariableColorEffect effect]];3.2 离散效果 —— Bounce(弹跳)
适合收到消息、完成操作等需要短暂吸引注意力的场景。
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"antenna.radiowaves.left.and.right"]];
// 弹跳两次
NSSymbolEffectOptions *options = [NSSymbolEffectOptions optionsWithRepeatCount:2];
[imageView addSymbolEffect:[NSSymbolBounceEffect effect] options:options animated:YES];
3.3 内容过渡 —— Replace(替换)
适合播放/暂停按钮、收藏/取消收藏等状态切换场景。
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"play.fill"]];
// 切换到暂停图标,使用 offUp 方向的替换动画
UIImage *pauseImage = [UIImage systemImageNamed:@"pause.fill"];
[imageView setSymbolImage:pauseImage
contentTransition:[[NSSymbolReplaceContentTransition effect] offUp]];
3.4 出现 / 消失 —— 无限行为
无限行为下,视图仍保留在视图层级中,布局不变,只是视觉上不可见。
UIImageView *moonView = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"moon.stars"]];
// 消失(视图依然占据布局空间)
[moonView addSymbolEffect:[NSSymbolDisappearEffect effect]];
// 重新出现
[moonView addSymbolEffect:[NSSymbolAppearEffect effect]];
3.5 出现 / 消失 —— 过渡行为(含完成回调)
过渡行为下,符号从视图层级真实移除,布局随之调整;可通过回调在动画结束后执行清理操作。
UIImageView *moonView = [[UIImageView alloc] initWithImage:[UIImage systemImageNamed:@"moon.stars"]];
[moonView addSymbolEffect:[NSSymbolDisappearEffect effect]
options:[NSSymbolEffectOptions options]
animated:YES
completionHandler:^(NSSymbolEffectCompletionContext *context) {
if (context.isFinished) {
// 动画播放完毕,从父视图移除
[context.sender removeFromSuperview];
}
}];两个空间的核心区别
- 无限行为 → 图像消失,视图仍在层级,布局不变
- 过渡行为 → 从层级中真实移除,周围视图重新布局
3.6 不带动画地设置效果
在某些场景(如页面刚出现时需要立即呈现"已缩放"状态)可以关闭动画:
// animated: NO 跳过过渡动画,直接呈现目标状态
[imageView addSymbolEffect:[NSSymbolDisappearEffect effect]
options:[NSSymbolEffectOptions options]
animated:NO];3.7 Variable Value(变量值)动画
通过改变 variableValue 来驱动符号内部的层级渲染,适合信号强度、音量等连续变化场景。
// 创建带变量值的符号(0.0 ~ 1.0)
UIImage *wifiImage = [UIImage systemImageNamed:@"wifi" variableValue:1.0 configuration:nil];
UIImageView *imageView = [[UIImageView alloc] initWithImage:wifiImage];
// 根据实时信号等级更新,系统自动插值动画
- (void)updateSignalLevel:(double)level {
UIImage *newImage = [UIImage systemImageNamed:@"wifi"
variableValue:level
configuration:nil];
[self.signalImageView setSymbolImage:newImage
contentTransition:[NSSymbolAutomaticContentTransition transition]];
}3.8 UIBarButtonItem 也能加动画
工具栏按钮同样支持符号动画 API,让操作栏更有生命感:
UIBarButtonItem *downloadItem = [[UIBarButtonItem alloc]
initWithImage:[UIImage systemImageNamed:@"arrow.down.circle"]
style:UIBarButtonItemStylePlain
target:self
action:@selector(startDownload)];
// 添加无限脉冲动画表示下载进行中
[downloadItem addSymbolEffect:[NSSymbolPulseEffect effect]];
// 下载完成后移除
[downloadItem removeSymbolEffectOfType:[NSSymbolPulseEffect effect]];4. 创建自定义动画符号
4.1 工作流概览
SF Symbols App 5 新增了动画查看器(Animation Viewer),可以在导出前预览并配置每种动画的行为。完整流程如下:
打开 SF Symbols App
↓
导入自定义 .svg 模板
↓
在 Animation Viewer 预览并选择动画效果
↓
添加图层注释(标记哪些图层参与动画)
↓
创建图层组(避免过度动画)
↓
选择目标平台与兼容性并导出
↓
将 .symbolset 拖入 Xcode Asset Catalog
4.2 图层组(Layer Groups)
默认情况下 SF Symbols 5 按图层运动,可能产生"零件四散"的奇怪效果。解决方案是将相关图层合并为图层组:
案例:魔方符号
✗ 按面分组 → 六个面各自弹跳,效果怪异
✓ 全部合并为一组 → 整个立方体一起弹跳,自然原则:在同一视觉深度、属于同一语义单元的图层应归入同一图层组。
5. 符号组件(Symbol Components)
5.1 什么是符号组件
Apple 为常见的"修饰图案"提供了现成组件,包括:
| 组件 | 语义 |
|---|---|
| Slash | 禁用 / 关闭 |
| Badge.plus | 添加 |
| Badge.minus | 移除 |
| Circle / Circle.fill | 圆形外壳 |
设计一致性原则:系统内置符号大量复用这些模式。自定义符号采用相同组件,可让用户在第一眼就感到"熟悉"。
5.2 使用方法
在 SF Symbols App 中:
- 右键点击自定义符号 → 将一个符号与组件合并
- 从组件库选择(例如 Slash)
- 系统自动生成新符号并处理:
- 正确的颜色注释
- 独立的斜线动画
- 多渲染模式适配(单色模式下自动变为擦除效果)

5.3 粗细补偿
符号组件内置可变模板支持(3 比例 × 9 粗细 = 27 种变体),系统会在符号尺寸缩小时自动加粗笔画,保证视觉重量与同尺寸的系统符号一致。
开发者可对极细体 / 黑体单独做微调(勾选 Override 后调整比例),中间粗细由系统自动插值。
6. 兼容性与导出
6.1 版本差异对照表
有一些动画虽然看上去很优美,但是一些版本中是不可以正常使用的
建议在实施动画之前要先做一层防爆,使用 @available 或版本判断即可
| 目标平台 | SF Symbols 版本 | 特性 |
|---|---|---|
| iOS 26+ / macOS Tahoe+ | 7 | Draw 动画、Variable Draw、渐变、增强 Magic Replace |
| iOS 17+ / macOS Sonoma+ | 5 | 完整动画支持、图层组、线框导出 |
| iOS 16 / macOS Ventura | 4 | 可变颜色、多色渲染,但无动作 |
| iOS 15 / macOS Monterey | 3 | 可变模板,无动画优化绘图 |
| iOS 14 / macOS Big Sur | 2 | 静态模板,无可变模板 |
6.2 导出时的兼容性设置
SF Symbols App 导出对话框中:
- 选择最新:生成带动画优化的完整绘图(线框视图)
- 选择 SF Symbols 3:生成更简单的绘图,旧系统可正常显示静态符号
- 选择 SF Symbols 2:生成静态模板,兼容最广
6.3 Objective-C 中的运行时版本判断
若需要在老系统上优雅降级(显示静态图标),使用 @available 或版本判断即可,符号动画 API 只在 iOS 17+ 可用:
if (@available(iOS 17.0, *)) {
[imageView addSymbolEffect:[NSSymbolVariableColorEffect effect].iterative.reversing];
} else {
// iOS 16 及以下:符号仍可正常显示,只是无动画
imageView.image = [UIImage systemImageNamed:@"wifi.router"];
}7. 最佳实践
7.1 优先使用 SF Symbols App 预览
在写代码前,先在 SF Symbols App 的 Animation Viewer 中预览效果,点击复制按钮可直接获取对应的 OC / Swift 代码片段,避免反复试错。
7.2 离散效果 vs 无限效果的选择
用户主动操作(点击、拖拽)→ 离散效果(Bounce、单次 Pulse)
系统后台状态(加载、连接)→ 无限效果(Variable Color、Scale)7.3 叠加多个效果时注意层次
同一 ImageView 可叠加多个效果,但要避免视觉噪音:
// 合理叠加:可变颜色 + 轻微缩放,表示"正在激活"
[imageView addSymbolEffect:[NSSymbolVariableColorEffect effect].iterative];
[imageView addSymbolEffect:[NSSymbolScaleEffect effectScalingUp]];
// 不建议:叠加三种以上动画,视觉混乱7.4 合理使用完成回调
过渡效果(Appear / Disappear)的完成回调适合处理:
- 动画结束后将视图从父视图移除
- 动画完成后触发下一步逻辑
[imageView addSymbolEffect:[NSSymbolDisappearEffect effect]
options:[NSSymbolEffectOptions options]
animated:YES
completionHandler:^(NSSymbolEffectCompletionContext *context) {
if (!context.isFinished) { return; } // 动画被中断,不处理
// 清理逻辑
[context.sender removeFromSuperview];
}];7.5 UISlider 内置动画
iOS 17 的 UISlider 在拇指滑到轨道两端时会自动触发弹跳动画。如果你的 UI 不需要这个效果,可以关闭:
self.slider.isSymbolAnimationEnabled = NO; // Swift 属性,OC 同名8. SF Symbols 7 新特性(WWDC 2025)
SF Symbols 7(随 iOS 26 / macOS Tahoe 推出)在动画和渲染层面带来了四项重要更新:Draw 动画、Variable Draw、Gradients(渐变)、以及增强的 Magic Replace。
8.1 Draw 动画(Draw On / Draw Off)
Draw 动画模拟手写笔画的有机流动,是 SF Symbols 7 最具表现力的新特性。符号从无到有(Draw On)或从有到无(Draw Off)地"描绘"自己。
三种播放模式
| 模式 | 说明 | 适用场景 |
|---|---|---|
byLayer(默认) |
各路径交错启动,产生渐进感 | 复杂多层符号 |
wholeSymbol |
所有层同时绘制,更简洁直接 | 简单符号、快速反馈 |
individually |
逐层依次绘制,等上一层完成再启动下一层 | 强调意图的分步动画 |
绘制方向由系统决定
Apple 根据符号语义预设了绘制方向:
- Wind 符号:从左到右(传达流动感)
- 阿拉伯字符:从右到左(匹配书写方向)
- 对称符号:从中心向两侧展开
- 含箭头的路径:箭头随描绘路径移动,末端才"落点"
UIKit / Objective-C 代码
// Draw On — 符号从无到有
[imageView addSymbolEffect:[NSSymbolDrawEffect effectDrawingOn]];
// Draw Off — 符号从有到无,带完成回调后移除视图
[imageView addSymbolEffect:[NSSymbolDrawEffect effectDrawingOff]
options:[NSSymbolEffectOptions options]
animated:YES
completionHandler:^(NSSymbolEffectCompletionContext *context) {
if (context.isFinished) {
[context.sender removeFromSuperview];
}
}];指定播放模式
// byLayer(默认,可省略)
[imageView addSymbolEffect:[[NSSymbolDrawEffect effectDrawingOn] byLayer]];
// wholeSymbol — 全符号同时绘制
[imageView addSymbolEffect:[[NSSymbolDrawEffect effectDrawingOn] wholeSymbol]];
// individually — 逐层依次绘制
[imageView addSymbolEffect:[[NSSymbolDrawEffect effectDrawingOn] individually]];使用版本判断降级
if (@available(iOS 26.0, *)) {
[imageView addSymbolEffect:[NSSymbolDrawEffect effectDrawingOn]];
} else {
// iOS 25 及以下:使用 Appear 替代
[imageView addSymbolEffect:[NSSymbolAppearEffect effect]];
}8.2 Variable Draw(可变绘制)
Variable Draw 是一种新的渲染预设(非动画效果),通过路径的"已绘制比例"直观表达进度或强度。与 Variable Color 不同,它改变的是路径的填充长度而非颜色透明度。
典型场景:
- 下载 / 上传进度条
- 温度计刻度
- 课程完成度
- 音量渐变指示
与 Variable Color 的区别
| 特性 | Variable Color | Variable Draw |
|---|---|---|
| 表达方式 | 图层透明度渐变 | 路径填充长度 |
| 视觉效果 | 颜色由深到浅 | 路径从头"画"到指定比例 |
| 适用场景 | 信号强度、激活状态 | 进度、强度 |
注意:同一符号可同时设计支持两种变量渲染,但运行时只能启用一种。使用
.default让系统选择该符号首选的模式。
UIKit / Objective-C 代码
// 创建带变量值的图像,variableValue: 0.0 ~ 1.0
UIImage *thermometerImage = [UIImage systemImageNamed:@"thermometer.sun"
variableValue:0.75
configuration:nil];
UIImageView *imageView = [[UIImageView alloc] initWithImage:thermometerImage];
// 更新进度,系统自动使用 Variable Draw 插值
- (void)updateProgress:(double)progress {
UIImage *newImage = [UIImage systemImageNamed:@"thermometer.sun"
variableValue:progress
configuration:nil];
// 使用 automatic 内容过渡,让系统选择最佳方式
[self.progressImageView setSymbolImage:newImage
contentTransition:[NSSymbolAutomaticContentTransition transition]];
}指定使用 Variable Draw 模式(iOS 26+)
if (@available(iOS 26.0, *)) {
// 显式指定渲染模式为 Draw(而非 Color)
UIImageSymbolConfiguration *config =
[UIImageSymbolConfiguration configurationWithVariableRenderingMode:UIImageSymbolVariableRenderingModeDraw];
UIImage *image = [UIImage systemImageNamed:@"thermometer.sun"
variableValue:0.5
configuration:config];
imageView.image = image;
}8.3 Gradients(渐变)
SF Symbols 7 支持对符号应用线性渐变,单一源颜色即可生成有层次感的视觉效果,在较大尺寸时表现尤为突出。
特性:
- 线性渐变,由单一颜色自动推导明暗
- 支持所有渲染模式(Monochrome / Hierarchical / Palette / Multicolor)
- 系统色和自定义色均可
UIKit / Objective-C 代码
// 单色渐变(Monochrome Gradient)
UIImageSymbolConfiguration *gradientConfig =
[UIImageSymbolConfiguration configurationWithHierarchicalColor:[UIColor systemBlueColor]];
// iOS 26 新增渐变配置(示意,具体 API 以 Xcode 文档为准)
UIImage *gradientImage = [UIImage systemImageNamed:@"star.fill"
withConfiguration:gradientConfig];
imageView.image = gradientImage;提示:在 SF Symbols App 7 中,可以在画廊视图直接预览渐变效果,找到满意的配置后点击"复制代码"按钮获取 OC / Swift 代码片段。
8.4 Magic Replace 增强
Magic Replace 在 SF Symbols 5 时首次引入,负责识别两个相关符号并平滑切换(例如 play.fill → pause.fill)。SF Symbols 7 对其进行了两项增强:
增强 1:Enclosure Matching(封闭匹配)
系统识别两个符号是否共享相同的"外壳"(如圆形、方形边框),若匹配则保留外壳不动,仅替换内部图层。
符号 A 符号 B
[ play ] → [ pause ]
↑ 圆形外壳保持静止,内部图标用 Draw 动画替换增强 2:自动集成 Draw 动画
新的 Magic Replace 会自动为替换过程加入 Draw 效果:
- 离场符号:Draw Off
- 入场符号:Draw On
// 无需额外配置,setSymbolImage:contentTransition: 自动使用增强版 Magic Replace
UIImage *pauseImage = [UIImage systemImageNamed:@"pause.circle.fill"];
[imageView setSymbolImage:pauseImage
contentTransition:[NSSymbolAutomaticContentTransition transition]];
// 系统自动判断是否有匹配封闭 → 应用增强 Magic Replace8.5 自定义符号的 Draw 注释(导航点)
要让自定义符号支持 Draw 动画,需要在 SF Symbols App 7 中为每条路径添加导航点(Guide Points),告诉系统绘制的起点、终点和路径走向
注意这一部分内容以文字形式讲解可能会有些问题,建议各位移步WWDC视频观看
导航点类型
| 类型 | 形状 | 作用 |
|---|---|---|
| Start Point | 空心圆 ○ | 路径起始位置 |
| End Point | 实心圆 ● | 路径结束位置 |
| Guide Point | 空心圆 ○ | 路径转折点(紧转弯处必加) |
| Corner Point | 菱形 ◇ | 锐角转折 |
不同路径类型的注释策略
简单直线路径(如 line.diagonal****):
1. 放置起点(Start Point)
2. 放置终点(End Point)
→ 完成,系统自动绘制方向多转折路径(如 scribble 涂鸦符号):
1. 在每个紧转折处额外放置 Guide Point
2. 保证路径平滑,避免绘制跳跃多路径符号(如 line.3.horizontal 三横线):
- 为每条线独立注释
- 可为不同路径设置不同绘制方向
- 拖动起点越过已有导航点 → 方向自动反转双向绘制(如 wave.3.up 波浪):
- 在路径中心放置起点
- 在两侧分别放置 Guide Point
- 系统识别为双向(显示两个箭头)
- 启用"对齐"确保各层起点对齐,保持对称封闭路径(如 circle 圆形):
- 首个导航点自动同时作为 Start 和 End(显示胶囊形状 ◇)
- 默认顺时针绘制
- 右键 → 切换为逆时针Attachment(附着)
对于箭头等"随路径移动但本身不是绘制对象"的元素,使用附着功能:
1. 将箭头图层拖动到已放置的导航点上
2. 箭头随该导航点沿路径移动
3. 要求箭头必须是独立路径(非混合形状)Weight 权重插值规则
| 规则 | 说明 |
|---|---|
| 主注释权重 | 只能在 Regular 权重中添加/删除导航点 |
| 自动插值 | Ultralight / Black 权重由系统自动插值 |
| 顺序一致性 | 各权重间导航点顺序必须相同,橙色标记 = 顺序错误 |
| 验证方式 | 开启"导航点编号"视图,逐一核对编号是否连续 |
Variable Draw 的自定义符号配置
在 SF Symbols App 7 中:
1. Settings → 启用 Variable Rendering
2. Layer List → 点击 Variable Draw 按钮
3. 仅勾选应展示进度的图层
(例:温度计只勾选刻度层,外框保持完整显示)
4. 使用变量渲染滑块(0 ~ 100%)预览效果附录:常用 Objective-C API 速查(更新至 SF Symbols 7)
| 操作 | 代码 |
|---|---|
| 添加无限效果 | [iv addSymbolEffect:effect] |
| 添加离散效果(N次) | [iv addSymbolEffect:effect options:[NSSymbolEffectOptions optionsWithRepeatCount:N] animated:YES] |
| 移除指定类型效果 | [iv removeSymbolEffectOfType:effect] |
| 内容过渡(替换) | [iv setSymbolImage:img contentTransition:transition] |
| 带完成回调的效果 | [iv addSymbolEffect:effect options:opt animated:YES completionHandler:^(NSSymbolEffectCompletionContext *ctx){...}] |
| 不带动画添加效果 | [iv addSymbolEffect:effect options:opt animated:NO] |
| 变量值图像 | [UIImage systemImageNamed:@"wifi" variableValue:0.5 configuration:nil] |
| Draw On(iOS 26+) | [iv addSymbolEffect:[NSSymbolDrawEffect effectDrawingOn]] |
| Draw Off(iOS 26+) | [iv addSymbolEffect:[NSSymbolDrawEffect effectDrawingOff]] |
| Draw 整体播放 | [[NSSymbolDrawEffect effectDrawingOn] wholeSymbol] |
| Draw 逐层播放 | [[NSSymbolDrawEffect effectDrawingOn] individually] |
引用资料
[1] WWDC23 Session 10258 — 在 App 中为符号添加动画效果
https://developer.apple.com/cn/videos/play/wwdc2023/10258
[2] WWDC23 Session 10257 — 创建带有动画效果的符号
https://developer.apple.com/cn/videos/play/wwdc2023/10257
[3] WWDC25 Session 337 — SF Symbols 7 新功能
https://developer.apple.com/videos/play/wwdc2025/337/
[4] WWDC23 Session 10197 — SF Symbols 5 的新功能
https://developer.apple.com/cn/videos/play/wwdc2023/10197
[5] SF Symbols App
https://developer.apple.com/sf-symbols/
[6] Apple 开发者文档 — NSSymbolEffect
https://developer.apple.com/documentation/symbols/nssymboleffect
[7] Apple 开发者文档 — UIImageView Symbol Effect APIs
https://developer.apple.com/documentation/uikit/uiimageview