axiom-sf-symbols-ref について
SwiftUI、UIKit、AppKit で SF Symbols を使う開発者向けの API リファレンススキルです。描画設定、シンボルエフェクト、プラットフォーム対応状況、カスタムシンボルのテンプレートを解説します。
主な機能
- 01SwiftUI、UIKit、AppKit の API
- 02描画モードと設定
- 03シンボルエフェクトとトランジション
- 04プラットフォーム対応状況
- 05カスタムシンボルのテンプレートガイド
活用シーン
- 01エフェクトの API 仕様と対応状況の確認
- 02シンボルの太さ、サイズ、色の設定
- 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を使用します - シンボル以外の一般的な SwiftUI アニメーションには
axiom-swiftui-animation-refを使用します
パート 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() を使用してレイヤーごとに色を明示的に指定します |
.multicolor | Apple が固定で用意している厳選カラーを使用します |
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 に準拠します。サブプロトコルで動作を定義します:
| プロトコル | トリガー | モディファイア | ループ |
|---|---|---|---|
DiscreteSymbolEffect | value:(Equatable) | .symbolEffect(_:options:value:) | いいえ |
IndefiniteSymbolEffect | isActive:(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 ファイルです。
- デザインツールから SVG として書き出します
- SF Symbols アプリに読み込みます(「File > Import」)
- テンプレートの種類を設定します:Monochrome、Hierarchical、Multicolor、Variable Color
- レンダリングモード用にレイヤーに注釈を付けます:
- Primaryレイヤー:Hierarchical で不透明度を最大にします
- Secondaryレイヤー:Hierarchical で不透明度を下げます
- Tertiaryレイヤー:Hierarchical で不透明度を最も低くします
- Palette モードに対応する場合は、レイヤーごとにPalette の色を設定します
- Xcode 用の
.svgテンプレートとして書き出します
Draw 注釈(SF Symbols 7)
カスタムシンボルで Draw アニメーションを有効にするには:
- SF Symbols 7 アプリでパスを選択します
- Draw 注釈パネルを開きます
- パス上にガイドポイントを配置します:
| ポイントの種類 | 表示 | 目的 |
|---|---|---|
| 開始点 | 白丸 | 描画を開始する位置 |
| 終了点 | 黒丸 | 描画を終了する位置 |
| コーナー | ひし形 | 方向が急に変わる位置 |
| 双方向 | 両矢印 | 中央から外側に向かう描画 |
| アタッチメント | リンクアイコン | 描画しない装飾的な接続 |
- 最小数:パスごとに 2 つのガイドポイント(開始点+終了点)
- Option キーを押しながらドラッグして、正確に配置します
- プレビュー画面で、すべてのウェイトを確認します
ウェイトの補間
カスタムシンボルには、少なくとも 3 種類のウェイトのデザインを含める必要があります。
- Ultralight(最も細い)
- Regular(中間)
- Black(最も太い)
システムは、これらの間の中間ウェイト(Thin、Light、Medium、Semibold、Bold、Heavy)を補間します。
Xcode への読み込み
- Xcode で Asset Catalog を開きます
- + > Symbol Image Setをクリックします
- SF Symbols アプリから書き出した
.svgをドラッグします - アセットカタログのシンボル:
Image("custom.symbol.name")。バンドルから読み込むシンボル:Image(systemName: "custom.symbol.name", bundle: .module)
パート 7:プラットフォーム対応状況一覧
レンダリングモード
| 機能 | 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+ |
| Draw On | 無期限 | 26+ | Tahoe+ | 26+ | 26+ | 26+ |
| Draw Off | 無期限 | 26+ | Tahoe+ | 26+ | 26+ | 26+ |
| 可変描画 | 値ベース | 26+ | Tahoe+ | 26+ | 26+ | 26+ |
| グラデーション塗りつぶし | レンダリング | 26+ | Tahoe+ | 26+ | 26+ | 26+ |
効果の動作カテゴリ
| カテゴリ | 動作 | トリガー方法 |
|---|---|---|
| 離散 | 1 回限りのアニメーションで、静止状態に戻ります | .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 は自動的に適応します。カスタムシンボルでこれを適切にサポートするには、ウェイトのバリエーションが必要です。
Dynamic Type
.font() でサイズを指定したシンボルは、Dynamic Type に合わせて自動的に拡大縮小されます。明示的なポイントサイズ(.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 以降(Wiggle/Rotate/Breathe)、iOS 26 以降(Draw、グラデーション)