axiom-sf-symbols-ref by charleswiltgen/axiom
npx skills add https://github.com/charleswiltgen/axiom --skill axiom-sf-symbols-ref在以下情况下使用:
axiom-sf-symbols 获取决策树、反模式、故障排除以及何时使用哪种效果axiom-swiftui-animation-ref 获取通用的 SwiftUI 动画(非符号相关)// 基本显示
Image(systemName: "star.fill")
// 带标签(图标 + 文本)
Label("Favorites", systemImage: "star.fill")
// 字体大小 — 符号随文本缩放
Image(systemName: "star.fill")
.font(.title)
// 图像缩放比例 — 不改变字体的相对大小调整
Image(systemName: "star.fill")
.imageScale(.large) // .small, .medium, .large
// 显式点大小
Image(systemName: "star.fill")
.font(.system(size: 24))
// 字重 — 匹配 SF Pro 字体字重
Image(systemName: "star.fill")
.fontWeight(.bold) // .ultraLight 到 .black
// 符号变体 — 编程方式设置 .fill, .circle, .square, .slash
Image(systemName: "person")
.symbolVariant(.circle.fill) // 渲染为 person.circle.fill
// 变量值 — 0.0 到 1.0,控制符号填充程度
Image(systemName: "speaker.wave.3.fill", variableValue: 0.5)
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
// 基本显示
let image = UIImage(systemName: "star.fill")
imageView.image = image
// 配置 — 点大小和字重
let config = UIImage.SymbolConfiguration(pointSize: 24, weight: .bold)
let image = UIImage(systemName: "star.fill", withConfiguration: config)
// 配置 — 文本样式(随动态类型缩放)
let config = UIImage.SymbolConfiguration(textStyle: .title1)
let image = UIImage(systemName: "star.fill", withConfiguration: config)
// 配置 — 缩放比例
let config = UIImage.SymbolConfiguration(scale: .large) // .small, .medium, .large
// 组合配置
let sizeConfig = UIImage.SymbolConfiguration(pointSize: 24, weight: .bold, scale: .large)
// 变量值
let image = UIImage(systemName: "speaker.wave.3.fill", variableValue: 0.5)
// 基本显示
let image = NSImage(systemSymbolName: "star.fill", accessibilityDescription: "Favorite")
// 配置
let config = NSImage.SymbolConfiguration(pointSize: 24, weight: .bold)
let configured = image?.withSymbolConfiguration(config)
// 单色(默认)
Image(systemName: "cloud.rain.fill")
.foregroundStyle(.blue)
// 层级 — 基于单一颜色的深度效果
Image(systemName: "cloud.rain.fill")
.symbolRenderingMode(.hierarchical)
.foregroundStyle(.blue)
// 调色板 — 每层使用显式颜色
Image(systemName: "cloud.rain.fill")
.symbolRenderingMode(.palette)
.foregroundStyle(.white, .blue)
// 对于 3 层符号:
.foregroundStyle(.red, .white, .blue)
// 多色 — Apple 精选的颜色
Image(systemName: "cloud.rain.fill")
.symbolRenderingMode(.multicolor)
// 首选渲染模式 — 使用符号的首选模式
// 如果符号不支持,会优雅地回退
Image(systemName: "cloud.rain.fill")
.symbolRenderingMode(.monochrome) // 显式单色
| 值 | 描述 |
|---|---|
.monochrome | 所有图层使用单一颜色(默认) |
.hierarchical | 单一颜色,每层自动调整不透明度 |
.palette | 通过 .foregroundStyle() 为每层指定显式颜色 |
.multicolor | Apple 固定的精选颜色 |
// 层级
let config = UIImage.SymbolConfiguration(hierarchicalColor: .systemBlue)
imageView.preferredSymbolConfiguration = config
// 调色板
let config = UIImage.SymbolConfiguration(paletteColors: [.white, .systemBlue])
imageView.preferredSymbolConfiguration = config
// 多色
let config = UIImage.SymbolConfiguration.preferringMulticolor()
imageView.preferredSymbolConfiguration = config
// 单色 — 只需设置 tintColor
imageView.tintColor = .systemBlue
let sizeConfig = UIImage.SymbolConfiguration(pointSize: 24, weight: .bold)
let colorConfig = UIImage.SymbolConfiguration(paletteColors: [.white, .blue, .gray])
let combined = sizeConfig.applying(colorConfig)
imageView.preferredSymbolConfiguration = combined
所有符号效果都遵循 SymbolEffect。子协议定义行为:
| 协议 | 触发条件 | 修饰符 | 循环 |
|---|---|---|---|
DiscreteSymbolEffect | value: (Equatable) | .symbolEffect(_:options:value:) | 否 |
IndefiniteSymbolEffect | isActive: (Bool) | .symbolEffect(_:options:isActive:) | 是 |
TransitionSymbolEffect | 视图生命周期 | .transition(.symbolEffect(_:)) | 否 |
ContentTransitionSymbolEffect | 符号更改 | .contentTransition(.symbolEffect(_:)) | 否 |
// 从视图层次结构中移除所有符号效果
Image(systemName: "star.fill")
.symbolEffectsRemoved() // 移除所有效果
.symbolEffectsRemoved(false) // 重新启用效果
// 速度乘数
.symbolEffect(.bounce, options: .speed(2.0), value: count)
// 重复次数
.symbolEffect(.bounce, options: .repeat(3), value: count)
// 连续重复
.symbolEffect(.pulse, options: .repeat(.continuous), isActive: true)
// 非重复(对于无限效果,运行一次后保持)
.symbolEffect(.breathe, options: .nonRepeating, isActive: true)
// 组合
.symbolEffect(.wiggle, options: .repeat(5).speed(1.5), value: count)
协议 : DiscreteSymbolEffect
// 离散 — 值改变时触发
Image(systemName: "arrow.down.circle")
.symbolEffect(.bounce, value: downloadCount)
// 方向性
.symbolEffect(.bounce.up, value: count)
.symbolEffect(.bounce.down, value: count)
// 按图层 — 不同图层在不同时间弹跳
.symbolEffect(.bounce.byLayer, value: count)
// 整个符号 — 整个符号一起弹跳
.symbolEffect(.bounce.wholeSymbol, value: count)
UIKit :
imageView.addSymbolEffect(.bounce)
// 带选项:
imageView.addSymbolEffect(.bounce, options: .repeat(3))
协议 : DiscreteSymbolEffect, IndefiniteSymbolEffect
// 无限 — 激活时持续进行
Image(systemName: "network")
.symbolEffect(.pulse, isActive: isConnecting)
// 离散 — 值改变时触发一次
.symbolEffect(.pulse, value: errorCount)
// 按图层
.symbolEffect(.pulse.byLayer, isActive: true)
// 整个符号
.symbolEffect(.pulse.wholeSymbol, isActive: true)
UIKit :
imageView.addSymbolEffect(.pulse)
imageView.removeSymbolEffect(ofType: PulseSymbolEffect.self)
协议 : DiscreteSymbolEffect, IndefiniteSymbolEffect
// 迭代 — 一次高亮一个图层
Image(systemName: "wifi")
.symbolEffect(.variableColor.iterative, isActive: isSearching)
// 累积 — 逐步填充图层
.symbolEffect(.variableColor.cumulative, isActive: true)
// 反转 — 来回循环
.symbolEffect(.variableColor.iterative.reversing, isActive: true)
// 隐藏非活动图层(淡化未高亮的图层)
.symbolEffect(.variableColor.iterative.hideInactiveLayers, isActive: true)
// 调暗非活动图层(略微降低未高亮图层的不透明度)
.symbolEffect(.variableColor.iterative.dimInactiveLayers, isActive: true)
UIKit :
imageView.addSymbolEffect(.variableColor.iterative)
imageView.removeSymbolEffect(ofType: VariableColorSymbolEffect.self)
协议 : IndefiniteSymbolEffect
// 放大
Image(systemName: "mic.fill")
.symbolEffect(.scale.up, isActive: isRecording)
// 缩小
.symbolEffect(.scale.down, isActive: isMuted)
// 按图层
.symbolEffect(.scale.up.byLayer, isActive: true)
// 整个符号
.symbolEffect(.scale.up.wholeSymbol, isActive: true)
UIKit :
imageView.addSymbolEffect(.scale.up)
imageView.removeSymbolEffect(ofType: ScaleSymbolEffect.self)
协议 : DiscreteSymbolEffect, IndefiniteSymbolEffect
// 离散
Image(systemName: "bell.fill")
.symbolEffect(.wiggle, value: notificationCount)
// 方向性
.symbolEffect(.wiggle.left, value: count)
.symbolEffect(.wiggle.right, value: count)
.symbolEffect(.wiggle.forward, value: count) // 支持 RTL
.symbolEffect(.wiggle.backward, value: count) // 支持 RTL
.symbolEffect(.wiggle.up, value: count)
.symbolEffect(.wiggle.down, value: count)
.symbolEffect(.wiggle.clockwise, value: count)
.symbolEffect(.wiggle.counterClockwise, value: count)
// 自定义角度
.symbolEffect(.wiggle.custom(angle: .degrees(15)), value: count)
// 按图层
.symbolEffect(.wiggle.byLayer, value: count)
UIKit :
imageView.addSymbolEffect(.wiggle)
协议 : DiscreteSymbolEffect, IndefiniteSymbolEffect
// 无限旋转
Image(systemName: "gear")
.symbolEffect(.rotate, isActive: isProcessing)
// 方向
.symbolEffect(.rotate.clockwise, isActive: true)
.symbolEffect(.rotate.counterClockwise, isActive: true)
// 按图层 — 仅特定图层旋转(例如,风扇叶片)
.symbolEffect(.rotate.byLayer, isActive: true)
UIKit :
imageView.addSymbolEffect(.rotate)
imageView.removeSymbolEffect(ofType: RotateSymbolEffect.self)
协议 : DiscreteSymbolEffect, IndefiniteSymbolEffect
// 基本呼吸效果
Image(systemName: "heart.fill")
.symbolEffect(.breathe, isActive: isMonitoring)
// 纯缩放 — 仅缩放
.symbolEffect(.breathe.plain, isActive: true)
// 脉冲 — 缩放 + 不透明度变化
.symbolEffect(.breathe.pulse, isActive: true)
// 按图层
.symbolEffect(.breathe.byLayer, isActive: true)
UIKit :
imageView.addSymbolEffect(.breathe)
imageView.removeSymbolEffect(ofType: BreatheSymbolEffect.self)
协议 : TransitionSymbolEffect
// SwiftUI 过渡
if showSymbol {
Image(systemName: "checkmark.circle.fill")
.transition(.symbolEffect(.appear))
}
if showSymbol {
Image(systemName: "xmark.circle.fill")
.transition(.symbolEffect(.disappear))
}
// 方向性
.transition(.symbolEffect(.appear.up))
.transition(.symbolEffect(.appear.down))
.transition(.symbolEffect(.disappear.up))
.transition(.symbolEffect(.disappear.down))
// 按图层
.transition(.symbolEffect(.appear.byLayer))
// 整个符号
.transition(.symbolEffect(.appear.wholeSymbol))
UIKit (作为效果,而非过渡):
// 使符号出现
imageView.addSymbolEffect(.appear)
// 使符号消失
imageView.addSymbolEffect(.disappear)
// 消失后出现
imageView.addSymbolEffect(.appear) // 重新显示隐藏的符号
协议 : ContentTransitionSymbolEffect
// SwiftUI 内容过渡
Image(systemName: isFavorite ? "star.fill" : "star")
.contentTransition(.symbolEffect(.replace))
// 方向性变体
.contentTransition(.symbolEffect(.replace.downUp))
.contentTransition(.symbolEffect(.replace.upUp))
.contentTransition(.symbolEffect(.replace.offUp))
// 按图层
.contentTransition(.symbolEffect(.replace.byLayer))
// 整个符号
.contentTransition(.symbolEffect(.replace.wholeSymbol))
// 魔法替换 — iOS 18+ 默认,变形共享元素
// 对结构相关的符号对自动生效:star ↔ star.fill, pause.fill ↔ play.fill
.contentTransition(.symbolEffect(.replace))
// 显式魔法替换,为不相关的符号提供回退
.contentTransition(.symbolEffect(.replace.magic(fallback: .replace.downUp)))
UIKit :
// 使用替换过渡更改符号
let newImage = UIImage(systemName: "star.fill")
imageView.setSymbolImage(newImage!, contentTransition: .replace)
// 方向性
imageView.setSymbolImage(newImage!, contentTransition: .replace.downUp)
// 无限 — 激活时绘制进入
Image(systemName: "checkmark.circle")
.symbolEffect(.drawOn, isActive: isComplete)
// 播放模式
.symbolEffect(.drawOn.byLayer, isActive: isActive)
.symbolEffect(.drawOn.wholeSymbol, isActive: isActive)
.symbolEffect(.drawOn.individually, isActive: isActive)
// 带选项
.symbolEffect(.drawOn, options: .speed(2.0), isActive: isActive)
.symbolEffect(.drawOn, options: .nonRepeating, isActive: isActive)
// 无限 — 激活时绘制退出
Image(systemName: "star.fill")
.symbolEffect(.drawOff, isActive: isHidden)
// 播放模式
.symbolEffect(.drawOff.byLayer, isActive: isActive)
.symbolEffect(.drawOff.wholeSymbol, isActive: isActive)
.symbolEffect(.drawOff.individually, isActive: isActive)
// 方向控制
.symbolEffect(.drawOff.nonReversed, isActive: isActive) // 沿绘制路径正向擦除
.symbolEffect(.drawOff.reversed, isActive: isActive) // 按相反顺序擦除
// 绘制开启
imageView.addSymbolEffect(.drawOn)
// 绘制关闭
imageView.addSymbolEffect(.drawOff)
// 移除
imageView.removeSymbolEffect(ofType: DrawOnSymbolEffect.self)
使用 SymbolVariableValueMode 来控制变量值的渲染方式。
// 可变绘制 — 根据值按比例绘制描边 (iOS 26+)
Image(systemName: "thermometer.high", variableValue: temperature)
.symbolVariableValueMode(.draw)
// 可变颜色 — 根据阈值设置图层不透明度 (iOS 17+, 默认)
Image(systemName: "wifi", variableValue: signalStrength)
.symbolVariableValueMode(.color)
| 选项 | 描述 |
|---|---|
.color | 根据阈值开关每个可变图层的不透明度(现有行为) |
.draw | 根据范围改变每个可变图层的绘制长度 |
约束 : 某些符号仅支持一种模式。设置不支持的模式没有可见效果。一个符号不能同时使用可变颜色和可变绘制。
使用 SymbolColorRenderingMode 从单一颜色自动生成渐变。
// 渐变填充 — 系统从源颜色生成轴向渐变
Image(systemName: "heart.fill")
.symbolColorRenderingMode(.gradient)
.foregroundStyle(.red)
// 适用于任何渲染模式
Image(systemName: "cloud.rain.fill")
.symbolRenderingMode(.hierarchical)
.symbolColorRenderingMode(.gradient)
.foregroundStyle(.blue)
| 选项 | 描述 |
|---|---|
.flat | 纯色填充(默认) |
.gradient | 从源颜色生成的轴向渐变 |
渐变在较大的符号尺寸下效果最佳,并适用于所有渲染模式。
struct PlayPauseButton: View {
@State private var isPlaying = false
var body: some View {
Button {
isPlaying.toggle()
} label: {
Image(systemName: isPlaying ? "pause.fill" : "play.fill")
.contentTransition(.symbolEffect(.replace))
}
.accessibilityLabel(isPlaying ? "Pause" : "Play")
}
}
struct DownloadButton: View {
@State private var state: DownloadState = .idle
var symbolName: String {
switch state {
case .idle: "arrow.down.circle"
case .downloading: "stop.circle"
case .complete: "checkmark.circle.fill"
}
}
var body: some View {
Button {
advanceState()
} label: {
Image(systemName: symbolName)
.contentTransition(.symbolEffect(.replace))
.symbolEffect(.pulse, isActive: state == .downloading)
}
}
}
struct FavoriteButton: View {
@Binding var isFavorite: Bool
@State private var bounceValue = 0
var body: some View {
Button {
isFavorite.toggle()
bounceValue += 1
} label: {
Image(systemName: isFavorite ? "star.fill" : "star")
.contentTransition(.symbolEffect(.replace))
.symbolEffect(.bounce, value: bounceValue)
.foregroundStyle(isFavorite ? .yellow : .gray)
}
}
}
自定义符号是具有特定图层注释的 SVG 文件:
.svg 模板用于 Xcode要在自定义符号上启用绘制动画:
| 点类型 | 视觉表示 | 用途 |
|---|---|---|
| 起点 | 空心圆 | 绘制开始处 |
| 终点 | 实心圆 | 绘制结束处 |
| 转角 | 菱形 | 方向急剧变化处 |
| 双向 | 双箭头 | 从中心向外绘制 |
| 附着点 | 链接图标 | 非绘制的装饰性连接点 |
自定义符号应至少包含 3 种字重变体的设计:
系统会为中间字重(细、轻、中等、半粗、粗、重)在这些之间进行插值。
.svg 文件Image("custom.symbol.name")。对于从 bundle 加载的符号:Image(systemName: "custom.symbol.name", bundle: .module)| 功能 | iOS | macOS | watchOS | tvOS | visionOS |
|---|---|---|---|---|---|
| 单色 | 13+ | 11+ | 6+ | 13+ | 1+ |
| 层级 | 15+ | 12+ | 8+ | 15+ | 1+ |
| 调色板 | 15+ | 12+ | 8+ | 15+ | 1+ |
| 多色 | 15+ | 12+ | 8+ | 15+ | 1+ |
| 变量值 | 16+ | 13+ | 9+ | 16+ | 1+ |
| 效果 | 类别 | iOS | macOS | watchOS | tvOS | visionOS |
|---|---|---|---|---|---|---|
| 弹跳 | 离散 | 17+ | 14+ | 10+ | 17+ | 1+ |
| 脉冲 | 离散/无限 | 17+ | 14+ | 10+ | 17+ | 1+ |
| 可变颜色 | 离散/无限 | 17+ | 14+ | 10+ | 17+ | 1+ |
| 缩放 | 无限 | 17+ | 14+ | 10+ | 17+ | 1+ |
| 出现 | 过渡 | 17+ | 14+ | 10+ | 17+ | 1+ |
| 消失 | 过渡 | 17+ | 14+ | 10+ | 17+ | 1+ |
| 替换 | 内容过渡 | 17+ | 14+ | 10+ | 17+ | 1+ |
| 摆动 | 离散/无限 | 18+ | 15+ | 11+ | 18+ | 2+ |
| 旋转 | 离散/无限 | 18+ | 15+ | 11+ | 18+ | 2+ |
| 呼吸 | 离散/无限 | 18+ | 15+ | 11+ | 18+ | 2+ |
| 绘制开启 | 无限 | 26+ | Tahoe+ | 26+ | 26+ | 26+ |
| 绘制关闭 | 无限 | 26+ | Tahoe+ | 26+ | 26+ | 26+ |
| 可变绘制 | 基于值 | 26+ | Tahoe+ | 26+ | 26+ | 26+ |
| 渐变填充 | 渲染 | 26+ | Tahoe+ | 26+ | 26+ | 26+ |
| 类别 | 作用 | 如何触发 |
|---|---|---|
| 离散 | 单次动画,返回静止状态 | .symbolEffect(_:value:) — 值改变时触发 |
| 无限 | 激活时循环播放 | .symbolEffect(_:isActive:) — true 时循环 |
| 过渡 | 在视图插入/移除时播放 | .transition(.symbolEffect(_:)) |
| 内容过渡 | 符号更改时播放 | .contentTransition(.symbolEffect(_:)) |
// 添加无限效果
imageView.addSymbolEffect(.pulse)
imageView.addSymbolEffect(.breathe)
imageView.addSymbolEffect(.rotate)
imageView.addSymbolEffect(.variableColor.iterative)
imageView.addSymbolEffect(.scale.up)
// 带选项添加
imageView.addSymbolEffect(.bounce, options: .repeat(3))
imageView.addSymbolEffect(.pulse, options: .speed(2.0))
// 带完成处理程序添加
imageView.addSymbolEffect(.bounce, options: .default) { context in
// 效果完成时调用
print("Bounce complete")
}
// 移除特定效果类型
imageView.removeSymbolEffect(ofType: PulseSymbolEffect.self)
imageView.removeSymbolEffect(ofType: ScaleSymbolEffect.self)
imageView.removeSymbolEffect(ofType: RotateSymbolEffect.self)
// 移除所有效果
imageView.removeAllSymbolEffects()
// 带选项移除
imageView.removeSymbolEffect(ofType: PulseSymbolEffect.self, options: .default)
// 带完成处理程序移除
imageView.removeSymbolEffect(ofType: PulseSymbolEffect.self) { context in
print("Pulse removed")
}
// 使用内容过渡替换
let newImage = UIImage(systemName: "pause.fill")!
imageView.setSymbolImage(newImage, contentTransition: .replace)
// 方向性替换
imageView.setSymbolImage(newImage, contentTransition: .replace.downUp)
imageView.setSymbolImage(newImage, contentTransition: .replace.upUp)
imageView.setSymbolImage(newImage, contentTransition: .replace.offUp)
// 带选项
imageView.setSymbolImage(newImage, contentTransition: .replace, options: .speed(2.0))
// 效果也适用于 UIBarButtonItem
barButtonItem.addSymbolEffect(.bounce)
barButtonItem.addSymbolEffect(.pulse, isActive: isLoading)
barButtonItem.removeSymbolEffect(ofType: PulseSymbolEffect.self)
// SwiftUI
Image(systemName: "star.fill")
.accessibilityLabel("Favorite")
// UIKit
let image = UIImage(systemName: "star.fill")
imageView.accessibilityLabel = "Favorite"
imageView.isAccessibilityElement = true
// Label 自动提供无障碍功能
Label("Settings", systemImage: "gear")
// VoiceOver 朗读:"Settings"
符号效果自动遵循 UIAccessibility.isReduceMotionEnabled。当“减弱动态效果”开启时:
不要尝试为此效果自行覆盖或检查。系统会处理。仅当效果带有语义含义时才进行干预:
// 如果脉冲传达连接状态,请提供文本标签
Image(systemName: "wifi")
.symbolEffect(.pulse, isActive: isConnecting)
.accessibilityLabel(isConnecting ? "Connecting to WiFi" : "WiFi connected")
当在无障碍设置中启用“粗体文本”时,SF Symbols 会自动适应。自定义符号需要字重变体来正确支持此功能。
使用 .font() 调整大小的符号会随动态类型自动缩放。使用显式点大小(.font(.system(size: 24)))调整大小的符号不会缩放。
// ✅ 随动态类型缩放
Image(systemName: "star.fill")
.font(.title)
// ❌ 固定大小,不缩放
Image(systemName: "star.fill")
.font(.system(size: 24))
struct NotificationBell: View {
let count: Int
var body: some View {
Image(systemName: count > 0 ? "bell.badge.fill" : "bell.fill")
.contentTransition(.symbolEffect(.replace))
.symbolEffect(.wiggle, value: count)
.symbolRenderingMode(.palette)
.foregroundStyle(count > 0 ? .red : .primary, .primary)
}
}
struct WiFiIndicator: View {
let strength: Double // 0.0 到 1.0
let isSearching: Bool
var body: some View {
Image(systemName: "wifi", variableValue: strength)
.symbolEffect(.variableColor.iterative, isActive: isSearching)
.symbolRenderingMode(.hierarchical)
.accessibilityLabel(
isSearching ? "Searching for WiFi" :
"WiFi strength: \(Int(strength * 100))%"
)
}
}
struct RecordButton: View {
@State private var isRecording = false
var body: some View {
Button {
isRecording.toggle()
} label: {
Image(systemName: isRecording ? "stop.circle.fill" : "record.circle")
.contentTransition(.symbolEffect(.replace))
.symbolEffect(.breathe.pulse, isActive: isRecording)
.font(.largeTitle)
.foregroundStyle(isRecording ? .red : .primary)
}
.accessibilityLabel(isRecording ? "Stop recording" : "Start recording")
}
}
struct TaskCheckbox: View {
@State private var isComplete = false
var body: some View {
Button {
isComplete.toggle()
} label: {
Image(systemName: isComplete ? "checkmark.circle.fill" : "circle")
.contentTransition(.symbolEffect(.replace))
.symbolEffect(.drawOn, isActive: isComplete)
.font(.title2)
.foregroundStyle(isComplete ? .green : .secondary)
}
.accessibilityLabel(isComplete ? "Completed" : "Not completed")
}
}
WWDC : 2023-10257, 2023-10258, 2024-10188, 2025-337
文档 : /symbols, /symbols/symboleffect, /symbols/bouncesymboleffect, /symbols/pulsesymboleffect, /symbols/variablecolorsymboleffect, /symbols/scalesymboleffect, /symbols/wigglesymboleffect, /symbols/rotatesymboleffect, /symbols/breathesymboleffect, /symbols/appearsymboleffect, /symbols/disappearsymboleffect, /symbols/replacesymboleffect, /symbols/drawonsymboleffect, /symbols/drawoffsymboleffect, /swiftui/image/symbolrenderingmode(_:), /uikit/uiimage/symbolconfiguration
技能 : axiom-sf-symbols, axiom-hig-ref, axiom-swiftui-animation-ref
最后更新 基于 WWDC 2023/10257-10258, WWDC 2024/10188, WWDC 2025/337 版本 iOS 13+ (显示), iOS 15+ (渲染模式), iOS 17+ (效果), iOS 18+ (摆动/旋转/呼吸), iOS 26+ (绘制, 渐变)
每周安装次数
113
仓库
GitHub 星标数
681
首次出现
2026年2月7日
安全审计
安装于
opencode106
gemini-cli104
codex103
github-copilot101
kimi-cli99
cursor99
Use when:
axiom-sf-symbols for decision trees, anti-patterns, troubleshooting, and when to use which effectaxiom-swiftui-animation-ref for general SwiftUI animation (non-symbol)// Basic display
Image(systemName: "star.fill")
// With Label (icon + text)
Label("Favorites", systemImage: "star.fill")
// Font sizing — symbol scales with text
Image(systemName: "star.fill")
.font(.title)
// Image scale — relative sizing without changing font
Image(systemName: "star.fill")
.imageScale(.large) // .small, .medium, .large
// Explicit point size
Image(systemName: "star.fill")
.font(.system(size: 24))
// Weight — matches SF Pro font weights
Image(systemName: "star.fill")
.fontWeight(.bold) // .ultraLight through .black
// Symbol variant — programmatic .fill, .circle, .square, .slash
Image(systemName: "person")
.symbolVariant(.circle.fill) // Renders person.circle.fill
// Variable value — 0.0 to 1.0, controls symbol fill level
Image(systemName: "speaker.wave.3.fill", variableValue: 0.5)
// Basic display
let image = UIImage(systemName: "star.fill")
imageView.image = image
// Configuration — point size and weight
let config = UIImage.SymbolConfiguration(pointSize: 24, weight: .bold)
let image = UIImage(systemName: "star.fill", withConfiguration: config)
// Configuration — text style (scales with Dynamic Type)
let config = UIImage.SymbolConfiguration(textStyle: .title1)
let image = UIImage(systemName: "star.fill", withConfiguration: config)
// Configuration — scale
let config = UIImage.SymbolConfiguration(scale: .large) // .small, .medium, .large
// Combine configurations
let sizeConfig = UIImage.SymbolConfiguration(pointSize: 24, weight: .bold, scale: .large)
// Variable value
let image = UIImage(systemName: "speaker.wave.3.fill", variableValue: 0.5)
// Basic display
let image = NSImage(systemSymbolName: "star.fill", accessibilityDescription: "Favorite")
// Configuration
let config = NSImage.SymbolConfiguration(pointSize: 24, weight: .bold)
let configured = image?.withSymbolConfiguration(config)
// Monochrome (default)
Image(systemName: "cloud.rain.fill")
.foregroundStyle(.blue)
// Hierarchical — depth from single color
Image(systemName: "cloud.rain.fill")
.symbolRenderingMode(.hierarchical)
.foregroundStyle(.blue)
// Palette — explicit color per layer
Image(systemName: "cloud.rain.fill")
.symbolRenderingMode(.palette)
.foregroundStyle(.white, .blue)
// For 3-layer symbols:
.foregroundStyle(.red, .white, .blue)
// Multicolor — Apple's curated colors
Image(systemName: "cloud.rain.fill")
.symbolRenderingMode(.multicolor)
// Preferred rendering mode — uses symbol's preferred mode
// Falls back gracefully if the symbol doesn't support it
Image(systemName: "cloud.rain.fill")
.symbolRenderingMode(.monochrome) // explicit monochrome
| Value | Description |
|---|---|
.monochrome | Single color for all layers (default) |
.hierarchical | Single color with automatic opacity per layer |
.palette | Explicit color per layer via .foregroundStyle() |
.multicolor | Apple's fixed curated colors |
// Hierarchical
let config = UIImage.SymbolConfiguration(hierarchicalColor: .systemBlue)
imageView.preferredSymbolConfiguration = config
// Palette
let config = UIImage.SymbolConfiguration(paletteColors: [.white, .systemBlue])
imageView.preferredSymbolConfiguration = config
// Multicolor
let config = UIImage.SymbolConfiguration.preferringMulticolor()
imageView.preferredSymbolConfiguration = config
// Monochrome — just set tintColor
imageView.tintColor = .systemBlue
let sizeConfig = UIImage.SymbolConfiguration(pointSize: 24, weight: .bold)
let colorConfig = UIImage.SymbolConfiguration(paletteColors: [.white, .blue, .gray])
let combined = sizeConfig.applying(colorConfig)
imageView.preferredSymbolConfiguration = combined
All symbol effects conform to SymbolEffect. Sub-protocols define behavior:
| Protocol | Trigger | Modifier | Loop |
|---|---|---|---|
DiscreteSymbolEffect | value: (Equatable) | .symbolEffect(_:options:value:) | No |
IndefiniteSymbolEffect | isActive: (Bool) | .symbolEffect(_:options:isActive:) | Yes |
TransitionSymbolEffect |
// Strip all symbol effects from a view hierarchy
Image(systemName: "star.fill")
.symbolEffectsRemoved() // Removes all effects
.symbolEffectsRemoved(false) // Re-enables effects
// Speed multiplier
.symbolEffect(.bounce, options: .speed(2.0), value: count)
// Repeat count
.symbolEffect(.bounce, options: .repeat(3), value: count)
// Continuous repeat
.symbolEffect(.pulse, options: .repeat(.continuous), isActive: true)
// Non-repeating (for indefinite effects, run once then hold)
.symbolEffect(.breathe, options: .nonRepeating, isActive: true)
// Combined
.symbolEffect(.wiggle, options: .repeat(5).speed(1.5), value: count)
Protocols : DiscreteSymbolEffect
// Discrete — triggers on value change
Image(systemName: "arrow.down.circle")
.symbolEffect(.bounce, value: downloadCount)
// Directional
.symbolEffect(.bounce.up, value: count)
.symbolEffect(.bounce.down, value: count)
// By Layer — different layers bounce at different times
.symbolEffect(.bounce.byLayer, value: count)
// Whole Symbol — entire symbol bounces together
.symbolEffect(.bounce.wholeSymbol, value: count)
UIKit :
imageView.addSymbolEffect(.bounce)
// With options:
imageView.addSymbolEffect(.bounce, options: .repeat(3))
Protocols : DiscreteSymbolEffect, IndefiniteSymbolEffect
// Indefinite — continuous while active
Image(systemName: "network")
.symbolEffect(.pulse, isActive: isConnecting)
// Discrete — triggers once on value change
.symbolEffect(.pulse, value: errorCount)
// By Layer
.symbolEffect(.pulse.byLayer, isActive: true)
// Whole Symbol
.symbolEffect(.pulse.wholeSymbol, isActive: true)
UIKit :
imageView.addSymbolEffect(.pulse)
imageView.removeSymbolEffect(ofType: PulseSymbolEffect.self)
Protocols : DiscreteSymbolEffect, IndefiniteSymbolEffect
// Iterative — highlights one layer at a time
Image(systemName: "wifi")
.symbolEffect(.variableColor.iterative, isActive: isSearching)
// Cumulative — progressively fills layers
.symbolEffect(.variableColor.cumulative, isActive: true)
// Reversing — cycles back and forth
.symbolEffect(.variableColor.iterative.reversing, isActive: true)
// Hide inactive layers (dims non-highlighted layers)
.symbolEffect(.variableColor.iterative.hideInactiveLayers, isActive: true)
// Dim inactive layers (slightly reduces opacity of non-highlighted)
.symbolEffect(.variableColor.iterative.dimInactiveLayers, isActive: true)
UIKit :
imageView.addSymbolEffect(.variableColor.iterative)
imageView.removeSymbolEffect(ofType: VariableColorSymbolEffect.self)
Protocols : IndefiniteSymbolEffect
// Scale up
Image(systemName: "mic.fill")
.symbolEffect(.scale.up, isActive: isRecording)
// Scale down
.symbolEffect(.scale.down, isActive: isMuted)
// By Layer
.symbolEffect(.scale.up.byLayer, isActive: true)
// Whole Symbol
.symbolEffect(.scale.up.wholeSymbol, isActive: true)
UIKit :
imageView.addSymbolEffect(.scale.up)
imageView.removeSymbolEffect(ofType: ScaleSymbolEffect.self)
Protocols : DiscreteSymbolEffect, IndefiniteSymbolEffect
// Discrete
Image(systemName: "bell.fill")
.symbolEffect(.wiggle, value: notificationCount)
// Directional
.symbolEffect(.wiggle.left, value: count)
.symbolEffect(.wiggle.right, value: count)
.symbolEffect(.wiggle.forward, value: count) // RTL-aware
.symbolEffect(.wiggle.backward, value: count) // RTL-aware
.symbolEffect(.wiggle.up, value: count)
.symbolEffect(.wiggle.down, value: count)
.symbolEffect(.wiggle.clockwise, value: count)
.symbolEffect(.wiggle.counterClockwise, value: count)
// Custom angle
.symbolEffect(.wiggle.custom(angle: .degrees(15)), value: count)
// By Layer
.symbolEffect(.wiggle.byLayer, value: count)
UIKit :
imageView.addSymbolEffect(.wiggle)
Protocols : DiscreteSymbolEffect, IndefiniteSymbolEffect
// Indefinite rotation
Image(systemName: "gear")
.symbolEffect(.rotate, isActive: isProcessing)
// Direction
.symbolEffect(.rotate.clockwise, isActive: true)
.symbolEffect(.rotate.counterClockwise, isActive: true)
// By Layer — only specific layers rotate (e.g., fan blades)
.symbolEffect(.rotate.byLayer, isActive: true)
UIKit :
imageView.addSymbolEffect(.rotate)
imageView.removeSymbolEffect(ofType: RotateSymbolEffect.self)
Protocols : DiscreteSymbolEffect, IndefiniteSymbolEffect
// Basic breathe
Image(systemName: "heart.fill")
.symbolEffect(.breathe, isActive: isMonitoring)
// Plain — scale only
.symbolEffect(.breathe.plain, isActive: true)
// Pulse — scale + opacity variation
.symbolEffect(.breathe.pulse, isActive: true)
// By Layer
.symbolEffect(.breathe.byLayer, isActive: true)
UIKit :
imageView.addSymbolEffect(.breathe)
imageView.removeSymbolEffect(ofType: BreatheSymbolEffect.self)
Protocols : TransitionSymbolEffect
// SwiftUI transition
if showSymbol {
Image(systemName: "checkmark.circle.fill")
.transition(.symbolEffect(.appear))
}
if showSymbol {
Image(systemName: "xmark.circle.fill")
.transition(.symbolEffect(.disappear))
}
// Directional
.transition(.symbolEffect(.appear.up))
.transition(.symbolEffect(.appear.down))
.transition(.symbolEffect(.disappear.up))
.transition(.symbolEffect(.disappear.down))
// By Layer
.transition(.symbolEffect(.appear.byLayer))
// Whole Symbol
.transition(.symbolEffect(.appear.wholeSymbol))
UIKit (as effect, not transition):
// Make symbol appear
imageView.addSymbolEffect(.appear)
// Make symbol disappear
imageView.addSymbolEffect(.disappear)
// Appear after disappear
imageView.addSymbolEffect(.appear) // re-shows hidden symbol
Protocols : ContentTransitionSymbolEffect
// SwiftUI content transition
Image(systemName: isFavorite ? "star.fill" : "star")
.contentTransition(.symbolEffect(.replace))
// Directional variants
.contentTransition(.symbolEffect(.replace.downUp))
.contentTransition(.symbolEffect(.replace.upUp))
.contentTransition(.symbolEffect(.replace.offUp))
// By Layer
.contentTransition(.symbolEffect(.replace.byLayer))
// Whole Symbol
.contentTransition(.symbolEffect(.replace.wholeSymbol))
// Magic Replace — default in iOS 18+, morphs shared elements
// Automatic for structurally related pairs: star ↔ star.fill, pause.fill ↔ play.fill
.contentTransition(.symbolEffect(.replace))
// Explicit Magic Replace with fallback for unrelated symbols
.contentTransition(.symbolEffect(.replace.magic(fallback: .replace.downUp)))
UIKit :
// Change symbol with Replace transition
let newImage = UIImage(systemName: "star.fill")
imageView.setSymbolImage(newImage!, contentTransition: .replace)
// Directional
imageView.setSymbolImage(newImage!, contentTransition: .replace.downUp)
// Indefinite — draws in while active
Image(systemName: "checkmark.circle")
.symbolEffect(.drawOn, isActive: isComplete)
// Playback modes
.symbolEffect(.drawOn.byLayer, isActive: isActive)
.symbolEffect(.drawOn.wholeSymbol, isActive: isActive)
.symbolEffect(.drawOn.individually, isActive: isActive)
// With options
.symbolEffect(.drawOn, options: .speed(2.0), isActive: isActive)
.symbolEffect(.drawOn, options: .nonRepeating, isActive: isActive)
// Indefinite — draws out while active
Image(systemName: "star.fill")
.symbolEffect(.drawOff, isActive: isHidden)
// Playback modes
.symbolEffect(.drawOff.byLayer, isActive: isActive)
.symbolEffect(.drawOff.wholeSymbol, isActive: isActive)
.symbolEffect(.drawOff.individually, isActive: isActive)
// Direction control
.symbolEffect(.drawOff.nonReversed, isActive: isActive) // follows draw path forward
.symbolEffect(.drawOff.reversed, isActive: isActive) // erases in reverse order
// Draw On
imageView.addSymbolEffect(.drawOn)
// Draw Off
imageView.addSymbolEffect(.drawOff)
// Remove
imageView.removeSymbolEffect(ofType: DrawOnSymbolEffect.self)
Uses SymbolVariableValueMode to control how variable values are rendered.
// Variable Draw — draws stroke proportional to value (iOS 26+)
Image(systemName: "thermometer.high", variableValue: temperature)
.symbolVariableValueMode(.draw)
// Variable Color — sets layer opacity based on threshold (iOS 17+, default)
Image(systemName: "wifi", variableValue: signalStrength)
.symbolVariableValueMode(.color)
| Case | Description |
|---|---|
.color | Sets opacity of each variable layer on/off based on threshold (existing behavior) |
.draw | Changes drawn length of each variable layer based on range |
Constraint : Some symbols support only one mode. Setting an unsupported mode has no visible effect. A symbol cannot use both Variable Color and Variable Draw simultaneously.
Uses SymbolColorRenderingMode for automatic gradient generation from a single color.
// Gradient fill — system generates axial gradient from source color
Image(systemName: "heart.fill")
.symbolColorRenderingMode(.gradient)
.foregroundStyle(.red)
// Works with any rendering mode
Image(systemName: "cloud.rain.fill")
.symbolRenderingMode(.hierarchical)
.symbolColorRenderingMode(.gradient)
.foregroundStyle(.blue)
| Case | Description |
|---|---|
.flat | Solid color fill (default) |
.gradient | Axial gradient generated from source color |
Gradients are most effective at larger symbol sizes and work across all rendering modes.
struct PlayPauseButton: View {
@State private var isPlaying = false
var body: some View {
Button {
isPlaying.toggle()
} label: {
Image(systemName: isPlaying ? "pause.fill" : "play.fill")
.contentTransition(.symbolEffect(.replace))
}
.accessibilityLabel(isPlaying ? "Pause" : "Play")
}
}
struct DownloadButton: View {
@State private var state: DownloadState = .idle
var symbolName: String {
switch state {
case .idle: "arrow.down.circle"
case .downloading: "stop.circle"
case .complete: "checkmark.circle.fill"
}
}
var body: some View {
Button {
advanceState()
} label: {
Image(systemName: symbolName)
.contentTransition(.symbolEffect(.replace))
.symbolEffect(.pulse, isActive: state == .downloading)
}
}
}
struct FavoriteButton: View {
@Binding var isFavorite: Bool
@State private var bounceValue = 0
var body: some View {
Button {
isFavorite.toggle()
bounceValue += 1
} label: {
Image(systemName: isFavorite ? "star.fill" : "star")
.contentTransition(.symbolEffect(.replace))
.symbolEffect(.bounce, value: bounceValue)
.foregroundStyle(isFavorite ? .yellow : .gray)
}
}
}
Custom symbols are SVG files with specific layer annotations:
.svg template for XcodeTo enable Draw animations on custom symbols:
| Point Type | Visual | Purpose |
|---|---|---|
| Start | Open circle | Where drawing begins |
| End | Closed circle | Where drawing ends |
| Corner | Diamond | Sharp direction change |
| Bidirectional | Double arrow | Center-outward drawing |
| Attachment | Link icon | Non-drawing decorative connection |
Custom symbols should include designs for at least 3 weight variants:
The system interpolates between these for intermediate weights (Thin, Light, Medium, Semibold, Bold, Heavy).
.svg from SF Symbols appImage("custom.symbol.name"). For symbols loaded from a bundle: Image(systemName: "custom.symbol.name", bundle: .module)| Feature | iOS | macOS | watchOS | tvOS | visionOS |
|---|---|---|---|---|---|
| Monochrome | 13+ | 11+ | 6+ | 13+ | 1+ |
| Hierarchical | 15+ | 12+ | 8+ | 15+ | 1+ |
| Palette | 15+ | 12+ | 8+ | 15+ | 1+ |
| Multicolor | 15+ | 12+ | 8+ | 15+ | 1+ |
| Variable Value | 16+ | 13+ | 9+ | 16+ |
| Effect | Category | iOS | macOS | watchOS | tvOS | visionOS |
|---|---|---|---|---|---|---|
| Bounce | Discrete | 17+ | 14+ | 10+ | 17+ | 1+ |
| Pulse | Discrete/Indefinite | 17+ | 14+ | 10+ | 17+ | 1+ |
| Variable Color | Discrete/Indefinite | 17+ | 14+ | 10+ | 17+ | 1+ |
| Scale | Indefinite | 17+ | 14+ | 10+ | 17+ |
| Category | What It Does | How to Trigger |
|---|---|---|
| Discrete | One-shot animation, returns to rest | .symbolEffect(_:value:) — fires when value changes |
| Indefinite | Loops while active | .symbolEffect(_:isActive:) — loops while true |
| Transition | Plays on view insert/remove | .transition(.symbolEffect(_:)) |
| Content Transition | Plays when symbol changes | .contentTransition(.symbolEffect(_:)) |
// Add indefinite effect
imageView.addSymbolEffect(.pulse)
imageView.addSymbolEffect(.breathe)
imageView.addSymbolEffect(.rotate)
imageView.addSymbolEffect(.variableColor.iterative)
imageView.addSymbolEffect(.scale.up)
// Add with options
imageView.addSymbolEffect(.bounce, options: .repeat(3))
imageView.addSymbolEffect(.pulse, options: .speed(2.0))
// Add with completion handler
imageView.addSymbolEffect(.bounce, options: .default) { context in
// Called when effect finishes
print("Bounce complete")
}
// Remove specific effect type
imageView.removeSymbolEffect(ofType: PulseSymbolEffect.self)
imageView.removeSymbolEffect(ofType: ScaleSymbolEffect.self)
imageView.removeSymbolEffect(ofType: RotateSymbolEffect.self)
// Remove all effects
imageView.removeAllSymbolEffects()
// Remove with options
imageView.removeSymbolEffect(ofType: PulseSymbolEffect.self, options: .default)
// Remove with completion
imageView.removeSymbolEffect(ofType: PulseSymbolEffect.self) { context in
print("Pulse removed")
}
// Replace with content transition
let newImage = UIImage(systemName: "pause.fill")!
imageView.setSymbolImage(newImage, contentTransition: .replace)
// Directional replace
imageView.setSymbolImage(newImage, contentTransition: .replace.downUp)
imageView.setSymbolImage(newImage, contentTransition: .replace.upUp)
imageView.setSymbolImage(newImage, contentTransition: .replace.offUp)
// With options
imageView.setSymbolImage(newImage, contentTransition: .replace, options: .speed(2.0))
// Effects also work on UIBarButtonItem
barButtonItem.addSymbolEffect(.bounce)
barButtonItem.addSymbolEffect(.pulse, isActive: isLoading)
barButtonItem.removeSymbolEffect(ofType: PulseSymbolEffect.self)
// SwiftUI
Image(systemName: "star.fill")
.accessibilityLabel("Favorite")
// UIKit
let image = UIImage(systemName: "star.fill")
imageView.accessibilityLabel = "Favorite"
imageView.isAccessibilityElement = true
// Label automatically provides accessibility
Label("Settings", systemImage: "gear")
// VoiceOver reads: "Settings"
Symbol effects automatically respect UIAccessibility.isReduceMotionEnabled. When Reduce Motion is on:
Do not attempt to override or check this yourself for effects. The system handles it. Only intervene if effects carry semantic meaning:
// If the pulsing conveys connection status, provide a text label
Image(systemName: "wifi")
.symbolEffect(.pulse, isActive: isConnecting)
.accessibilityLabel(isConnecting ? "Connecting to WiFi" : "WiFi connected")
SF Symbols automatically adapt when Bold Text is enabled in Accessibility settings. Custom symbols need weight variants to support this properly.
Symbols sized with .font() scale automatically with Dynamic Type. Symbols sized with explicit point sizes (.font(.system(size: 24))) do not scale.
// ✅ Scales with Dynamic Type
Image(systemName: "star.fill")
.font(.title)
// ❌ Fixed size, does not scale
Image(systemName: "star.fill")
.font(.system(size: 24))
struct NotificationBell: View {
let count: Int
var body: some View {
Image(systemName: count > 0 ? "bell.badge.fill" : "bell.fill")
.contentTransition(.symbolEffect(.replace))
.symbolEffect(.wiggle, value: count)
.symbolRenderingMode(.palette)
.foregroundStyle(count > 0 ? .red : .primary, .primary)
}
}
struct WiFiIndicator: View {
let strength: Double // 0.0 to 1.0
let isSearching: Bool
var body: some View {
Image(systemName: "wifi", variableValue: strength)
.symbolEffect(.variableColor.iterative, isActive: isSearching)
.symbolRenderingMode(.hierarchical)
.accessibilityLabel(
isSearching ? "Searching for WiFi" :
"WiFi strength: \(Int(strength * 100))%"
)
}
}
struct RecordButton: View {
@State private var isRecording = false
var body: some View {
Button {
isRecording.toggle()
} label: {
Image(systemName: isRecording ? "stop.circle.fill" : "record.circle")
.contentTransition(.symbolEffect(.replace))
.symbolEffect(.breathe.pulse, isActive: isRecording)
.font(.largeTitle)
.foregroundStyle(isRecording ? .red : .primary)
}
.accessibilityLabel(isRecording ? "Stop recording" : "Start recording")
}
}
struct TaskCheckbox: View {
@State private var isComplete = false
var body: some View {
Button {
isComplete.toggle()
} label: {
Image(systemName: isComplete ? "checkmark.circle.fill" : "circle")
.contentTransition(.symbolEffect(.replace))
.symbolEffect(.drawOn, isActive: isComplete)
.font(.title2)
.foregroundStyle(isComplete ? .green : .secondary)
}
.accessibilityLabel(isComplete ? "Completed" : "Not completed")
}
}
WWDC : 2023-10257, 2023-10258, 2024-10188, 2025-337
Docs : /symbols, /symbols/symboleffect, /symbols/bouncesymboleffect, /symbols/pulsesymboleffect, /symbols/variablecolorsymboleffect, /symbols/scalesymboleffect, /symbols/wigglesymboleffect, /symbols/rotatesymboleffect, /symbols/breathesymboleffect, /symbols/appearsymboleffect, /symbols/disappearsymboleffect, /symbols/replacesymboleffect, /symbols/drawonsymboleffect, /symbols/drawoffsymboleffect, /swiftui/image/symbolrenderingmode(_:), /uikit/uiimage/symbolconfiguration
Skills : axiom-sf-symbols, axiom-hig-ref, axiom-swiftui-animation-ref
Last Updated Based on WWDC 2023/10257-10258, WWDC 2024/10188, WWDC 2025/337 Version iOS 13+ (display), iOS 15+ (rendering modes), iOS 17+ (effects), iOS 18+ (Wiggle/Rotate/Breathe), iOS 26+ (Draw, Gradients)
Weekly Installs
113
Repository
GitHub Stars
681
First Seen
Feb 7, 2026
Security Audits
Gen Agent Trust HubPassSocketPassSnykPass
Installed on
opencode106
gemini-cli104
codex103
github-copilot101
kimi-cli99
cursor99
Clerk Swift iOS 原生集成指南:SwiftUI/UIKit 认证实现与快速开始
844 周安装
| View lifecycle |
.transition(.symbolEffect(_:)) |
| No |
ContentTransitionSymbolEffect | Symbol change | .contentTransition(.symbolEffect(_:)) | No |
| 1+ |
| 1+ |
| Appear | Transition | 17+ | 14+ | 10+ | 17+ | 1+ |
| Disappear | Transition | 17+ | 14+ | 10+ | 17+ | 1+ |
| Replace | Content Transition | 17+ | 14+ | 10+ | 17+ | 1+ |
| Wiggle | Discrete/Indefinite | 18+ | 15+ | 11+ | 18+ | 2+ |
| Rotate | Discrete/Indefinite | 18+ | 15+ | 11+ | 18+ | 2+ |
| Breathe | Discrete/Indefinite | 18+ | 15+ | 11+ | 18+ | 2+ |
| Draw On | Indefinite | 26+ | Tahoe+ | 26+ | 26+ | 26+ |
| Draw Off | Indefinite | 26+ | Tahoe+ | 26+ | 26+ | 26+ |
| Variable Draw | Value-based | 26+ | Tahoe+ | 26+ | 26+ | 26+ |
| Gradient Fill | Rendering | 26+ | Tahoe+ | 26+ | 26+ | 26+ |