mcpField
A
axiom-sf-symbols-ref

axiom-sf-symbols-ref

github.com/charleswiltgen设计与 UI1.2k150 次安装今天更新
代码仓库

关于 axiom-sf-symbols-ref

面向开发者的 SF Symbols API 参考技能,适用于 SwiftUI、UIKit 和 AppKit 界面开发,介绍渲染配置、符号效果、平台可用性及自定义符号模板。

主要功能

  1. 01SwiftUI、UIKit 和 AppKit API
  2. 02渲染模式与配置
  3. 03符号效果与过渡
  4. 04平台可用性说明
  5. 05自定义符号模板指导

适用场景

  1. 01查询效果的 API 签名与可用性
  2. 02配置符号字重、缩放或颜色
  3. 03构建符号过渡和动画

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/charleswiltgen/axiom --skill axiom-sf-symbols-ref

安装后在 Claude Code 中输入/axiom-sf-symbols-ref确认已加载。

详细介绍

SF Symbols — API 参考

何时使用此技能

适用于:

  • 需要渲染模式或符号效果的准确 API 签名
  • 需要 SwiftUI 符号 API 对应的 UIKit/AppKit API
  • 需要检查特定效果的平台可用性
  • 需要配置选项(字重、缩放、可变值)
  • 需要使用正确的模板结构创建自定义符号
相关技能
  • 使用 axiom-sf-symbols 查看决策树、反模式、故障排查,以及选择效果的建议
  • 使用 axiom-swiftui-animation-ref 了解常规 SwiftUI 动画(非符号动画)

第 1 部分:符号显示

SwiftUI
// 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)
UIKit
// 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)
AppKit
// Basic display
let image = NSImage(systemSymbolName: "star.fill", accessibilityDescription: "Favorite")

// Configuration
let config = NSImage.SymbolConfiguration(pointSize: 24, weight: .bold)
let configured = image?.withSymbolConfiguration(config)

第 2 部分:渲染模式

SwiftUI
// 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
SymbolRenderingMode 枚举
值描述
.monochrome所有图层使用单一颜色(默认)
.hierarchical使用单一颜色,并为每个图层自动设置不透明度
.palette通过 .foregroundStyle() 为每个图层指定颜色
.multicolorApple 精选的固定颜色
UIKit
// 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
组合配置(UIKit)
let sizeConfig = UIImage.SymbolConfiguration(pointSize: 24, weight: .bold)
let colorConfig = UIImage.SymbolConfiguration(paletteColors: [.white, .blue, .gray])
let combined = sizeConfig.applying(colorConfig)
imageView.preferredSymbolConfiguration = combined

第 3 部分:符号效果 — 完整 API

效果协议层级

所有符号效果都遵循 SymbolEffect。子协议定义其行为:

协议触发方式修饰符循环
DiscreteSymbolEffectvalue:(Equatable).symbolEffect(_:options:value:)否
IndefiniteSymbolEffectisActive:(Bool).symbolEffect(_:options:isActive:)是
TransitionSymbolEffect视图生命周期.transition(.symbolEffect(_:))否
ContentTransitionSymbolEffect符号变化.contentTransition(.symbolEffect(_:))否
移除所有效果(SwiftUI)
// Strip all symbol effects from a view hierarchy
Image(systemName: "star.fill")
    .symbolEffectsRemoved() // Removes all effects
    .symbolEffectsRemoved(false) // Re-enables effects
SymbolEffectOptions
// 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)

弹跳

协议: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))

脉冲

协议: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)

可变颜色

协议: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)

缩放

协议: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)

摆动(iOS 18+)

协议: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)

旋转(iOS 18+)

协议: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)

呼吸(iOS 18+)

协议: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)

出现和消失

协议: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(作为效果,而非过渡):

// Make symbol appear
imageView.addSymbolEffect(.appear)

// Make symbol disappear
imageView.addSymbolEffect(.disappear)

// Appear after disappear
imageView.addSymbolEffect(.appear) // re-shows hidden symbol

替换

协议: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)

第 4 部分:绘制效果(iOS 26+)

绘制出现
// 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
UIKit 绘制效果
// Draw On
imageView.addSymbolEffect(.drawOn)

// Draw Off
imageView.addSymbolEffect(.drawOff)

// Remove
imageView.removeSymbolEffect(ofType: DrawOnSymbolEffect.self)
可变绘制

使用 SymbolVariableValueMode 控制可变值的渲染方式。

// 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)
SymbolVariableValueMode 枚举(iOS 26+)
枚举项描述
.color根据阈值设置每个可变图层的不透明度(现有行为)
.draw根据范围改变每个可变图层的绘制长度

限制:某些符号仅支持一种模式。设置不受支持的模式不会产生可见效果。符号不能同时使用可变颜色和可变绘制。

渐变渲染(iOS 26+)

使用 SymbolColorRenderingMode 从单一颜色自动生成渐变。

// 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)
SymbolColorRenderingMode 枚举(iOS 26+)
枚举项描述
.flat纯色填充(默认)
.gradient根据源颜色生成的轴向渐变

渐变在符号尺寸较大时效果最佳,并且适用于所有渲染模式。


第 5 部分:内容过渡模式

使用替换效果切换符号
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)
        }
    }
}

第 6 部分:自定义符号

模板结构

自定义符号是带有特定图层注释的 SVG 文件:

  1. 从设计工具导出为 SVG
  2. 导入 SF Symbols 应用(File > Import)
  3. 设置模板类型:单色、分层、多色或可变颜色
  4. 为图层添加注释以设置渲染模式:
    • Primary 图层:在分层模式下不透明度为完全不透明
    • Secondary 图层:在分层模式下不透明度降低
    • Tertiary 图层:在分层模式下不透明度最低
  5. 如果要支持调色板模式,为每个图层设置调色板颜色
  6. 导出为 .svg 模板,以供 Xcode 使用
绘制注释(SF Symbols 7)

要为自定义符号启用绘制动画:

  1. 在 SF Symbols 7 应用中选择路径
  2. 打开绘制注释面板
  3. 在路径上放置引导点:
点类型外观用途
起点空心圆绘制开始的位置
终点实心圆绘制结束的位置
转角菱形方向急剧变化的位置
双向双箭头从中心向外绘制
附着点链接图标非绘制性装饰连接
  1. 最少:每条路径 2 个引导点(起点 + 终点)
  2. 按住 Option 并拖动以精确放置
  3. 在预览面板中测试所有字重
字重插值

自定义符号应至少包含 3 种字重变体的设计:

  • Ultralight(最细)
  • Regular(中等)
  • Black(最粗)

系统会在这些字重之间插值,生成中间字重(Thin、Light、Medium、Semibold、Bold、Heavy)。

导入 Xcode
  1. 在 Xcode 中打开资源目录
  2. 点击 + > 符号图像集
  3. 将从 SF Symbols 应用导出的 .svg 拖入
  4. 资源目录中的符号:Image("custom.symbol.name")。从包中加载的符号:Image(systemName: "custom.symbol.name", bundle: .module)

第 7 部分:平台可用性矩阵

渲染模式
功能iOSmacOSwatchOStvOSvisionOS
单色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+
符号效果
效果类别iOSmacOSwatchOStvOSvisionOS
弹跳离散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(_:))

第 8 部分:UIKit 完整参考

添加效果
// 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))
UIBarButtonItem 效果
// Effects also work on UIBarButtonItem
barButtonItem.addSymbolEffect(.bounce)
barButtonItem.addSymbolEffect(.pulse, isActive: isLoading)
barButtonItem.removeSymbolEffect(ofType: PulseSymbolEffect.self)

第 9 部分:辅助功能

标签
// 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"
减少动态效果

符号效果会自动遵循 UIAccessibility.isReduceMotionEnabled。启用“减少动态效果”后:

  • 大多数效果会简化或停用
  • 替换过渡会使用交叉淡化,而不是定向移动
  • 无限效果可能会简化为静态外观变化

不要尝试自行覆盖或检查效果。系统会处理这些情况。只有当效果具有语义含义时,才需要介入:

// 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 会自动适配。自定义符号需要提供不同字重的变体,才能正确支持此功能。

动态字体

使用 .font() 设置大小的符号会随动态字体自动缩放。使用显式字号(.font(.system(size: 24)))设置大小的符号不会缩放。

// ✅ Scales with Dynamic Type
Image(systemName: "star.fill")
    .font(.title)

// ❌ Fixed size, does not scale
Image(systemName: "star.fill")
    .font(.system(size: 24))

第 10 部分:常见模式

带效果的通知徽标
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)
    }
}
WiFi 信号强度指示器
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")
    }
}
使用 Draw 的多状态符号(iOS 26+)
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+(绘制、渐变)

评论

支持 Markdown