SwiftUIでSVGを使う:アセットの追加と色の制御
Xcodeの画像セットにSVGを追加し、アセット名で読み込みます。元の色とテンプレート描画を選び、実際のサイズで色、余白、アプリの結果を確認します。
目次
SwiftUIアプリに含める静的なSVGは、Xcodeのアセットカタログに入れ、アセット名で画像を読み込みます。その後、元の色を保つか、色を付けるシルエットにするかを決めます。AppleはXcode 12でSVG画像アセットを追加しました。リリースノートでは、iOS 13、iPadOS 13、macOS 10.15以降のデプロイ対象でベクターを保持すると記載しています。
カタログのワークフローは、アプリの実行中にSVGをダウンロードする方法とも、独自のSF Symbolを作る方法とも異なります。アートワークの変更やレンダラーパッケージの追加の前に、受け渡し経路を選びます。
この画像に必要な経路を選ぶ
SVGは元ファイルです。アプリが受け取り使用する方法で、次の手順が決まります。
| 必要なもの | 最初の経路 | 確認すること |
|---|---|---|
| バンドルする静的なロゴやイラスト | アセットカタログの通常の画像セット | アセット名、色、範囲、ビルド出力 |
| 実行時に渡されるSVGファイル | 明示的なSVG描画ソリューション | 対応機能と読み込み/エラー時の動作 |
| SwiftUIで形状を制御する図形 | ネイティブのShape/Pathコード | パスの移植、比率、スタイル |
| 文字のような太さと位置合わせを持つ独自のシンボル | SF Symbolsのテンプレートワークフロー | 必要なバリエーション、ガイド、注釈、検証 |
本記事は最初の経路を使います。小さな2色のカップなら、サンゴ色の湯気の色が失われることと、取っ手の穴が埋まることという、二つの誤りを見つけやすくなります。どちらも診断に複雑なイラストは必要ありません。
UIキットの準備ガイドは、一式を統一するためのより広い作業を扱っています。ここでは、採用した一つのSVGをSwiftUIのImageに渡す方法を考えます。
確認箇所が見える小さな元データを準備する
この独自の例をCupMark.svgとして保存します。
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
<path d="M12 26H43V45Q43 54 34 54H21Q12 54 12 45Z"
fill="#147D73"/>
<path d="M43 30H48Q55 30 55 37Q55 44 48 44H43"
fill="none" stroke="#147D73" stroke-width="5"/>
<path d="M24 19Q18 14 25 8M35 19Q29 14 36 8"
fill="none" stroke="#EB8067" stroke-width="4" stroke-linecap="round"/>
</svg>カップは青緑色、2本の湯気のストロークはサンゴ色、取っ手の内側は空白です。この3点を確認リストに入れます。文字、外部画像、フィルター、スクリプトを含まないSVGなので、カタログの実験用の小さな出発点になります。
自身のアートワークはインポート前に確認します。空のキャンバスが多すぎると、ビューの寸法が正しくてもアイコンが小さく見えます。白い背景の長方形はテンプレートのシルエットの一部になります。埋め込み写真は周囲のパスとは別種の内容のままです。埋め込みラスターの確認で区別できます。
編集可能なマスターは、アプリ用のコピーとは別に保持します。文字を含むアイコンでは、マスターで目的のフォントかアウトライン化の方針を決めます。SVGのフォント変更の手順を参照してください。SwiftUIの文字スタイルを変えても、画像内の文字の確認の代わりにはなりません。

通常の画像セットとして追加する
通常はAssets.xcassetsというアプリのアセットカタログを開きます。新しい画像セットを追加してCupMarkと名付け、SVGを適した画像欄にドラッグします。Appleのアセットカタログのガイドは、セットの作成、リソースの取り込み、Attributesインスペクターでのバリエーション設定を説明しています。
この例では画像セットを使います。元データの拡張子が.svgという理由だけで、シンボル画像のワークフローを選ばないでください。
インポート後は、カタログのプレビューとビルドの診断を確認します。カタログが画像を使うアプリターゲットに属していることも確認します。プラットフォームや外観のバリエーションがある場合は、プレビューがすべての構成を表すと思わず、該当する構成に目的の画像があることを確かめます。
CupMarkは以下で使う画像リソース名です。ダウンロードURLやデザインフォルダー内の元SVGのパスではありません。AppleのImageイニシャライザーは、バンドル内のリソースを名前で検索し、既定ではメインバンドルを使います。別のリソースバンドルに属するなら、そのバンドルを意図的に指定します。
引き継ぎメモでは、ファイル名とアセット名を区別します。チームメンバーが元のデザインファイル名を変えずにアセットセットを改名することもあり、コードは実際に読み込むリソース名に従う必要があります。
originalとtemplateの描画を比較する
CupMark画像セットを追加してから、このビューを使います。
import SwiftUI
struct CupComparison: View {
var body: some View {
HStack(spacing: 24) {
Image("CupMark")
.renderingMode(.original)
.resizable()
.scaledToFit()
.frame(width: 48, height: 48)
.accessibilityLabel("Cup with rising steam")
Image("CupMark")
.renderingMode(.template)
.resizable()
.scaledToFit()
.frame(width: 48, height: 48)
.foregroundStyle(Color.blue)
.accessibilityLabel("Cup with rising steam")
}
.padding()
}
}左は明示的にoriginal描画を要求します。右はtemplate描画を要求し、前景スタイルに青を指定します。Appleのテンプレート描画の資料は、非透明ピクセルを前景色にするモードと定義しています。シルエットとして扱うもので、一つのSVGパスだけの色を変える命令ではありません。
カップの場合、右側は湯気もカップも青になるはずです。サンゴ色と青緑色の違いは意図的になくなります。取っ手の穴は空いたままであるべきです。湯気とカップを独立して変える必要があるなら、一つのテンプレート画像にパスごとのスタイルを期待せず、各部品を別々に扱える構成を選びます。
修飾子はサイズの判断も明示します。resizable()は画像のサイズ変更を可能にし、scaledToFit()は48ポイントの枠内で縦横比を保持します。ビューの枠とアートワークのキャンバスは別の境界であり、SVG内の余白は元データの一部として残ります。
これは資料に基づいてプロジェクトで試す例で、ネイティブ描画テストの結果報告ではありません。使用予定の最小サイズも含め、実際にビルドしたアプリを確認します。48ポイントの鮮明なプレビューだけでは、16ポイントでも2本の湯気が有用に見えるとは確認できません。
ファイルを変える前に見えている結果を診断する
画像がない、色が変わった、小サイズのシルエットが悪い場合では、必要な修正が異なります。
| 症状 | 最初の確認 | 有用な次の操作 |
|---|---|---|
| 画像が出ない | リソース名、バンドル、ターゲット、カタログのビルド診断 | パスの編集前にリソース検索やインポートの問題を解決します |
| 全部が一色になる | originalとtemplateの描画 | 固定の多色アートワークにはoriginalを使います |
| 色が大きな長方形を埋める | 元データの不透明な背景 | マスターの不要な背景形状を削除します |
| マークが小さすぎる | SVGキャンバス内の空白 | キャンバスを直して再書き出しします |
| 湯気や狭い穴が不明瞭 | 最終表示サイズと元の細部 | 意図的に単純化し、小さい表示を確認します |
| デザインエディターと機能の結果が異なる | 該当するSVG機能とインポーター診断 | 単純な受け渡しコピーを試すか、別の対応形式を選びます |
一度に一つの層を変えます。元データに正しい穴がすでにあれば、トレースし直してもアセット名の誤字は直りません。検索は成功しているがtemplateモードで色の違いがなくなる場合、SVGに色を追加しても描画モードは変わりません。
見える文字の横にあるアイコンでは、コントロール全体の文脈でアクセシブルな名前を確認します。この例は比較用の各画像に説明を付けています。すでに名前のあるコントロールの横で装飾として繰り返し表示するアイコンには、別のアクセシビリティ処理が必要な場合があります。比較ビューのラベルをどの配置にも機械的に適用しないでください。
実行時SVGとSF Symbolsを別々に判断する
名前付きカタログ画像は、任意のSVG XMLを取得し解析するAPIではありません。ビルド後にファイルが届くなら、その入力を明示的に扱うレンダラーを選びます。たとえばSVGViewプロジェクトのREADMEは、SwiftUIで書いたSVGパーサーとレンダラーを説明しています。実際のファイルが使うSVG機能を評価してください。幅広い対応を目指すパッケージでも、入力一式がすべて正しく描画される証明にはなりません。
読み込み、失敗、非対応ファイルの動作も実行時機能の一部にします。必要なものがアセットカタログで扱える静的画像なら、古い回答にSwiftUIはSVGを使えないと書いてあるという理由だけでパッケージを追加しないでください。
独自のSF Symbolsは元データの要件が別です。Appleは、シンボルのバリエーションや位置合わせ情報を含むテンプレートによる作成と検証の手順を説明しています。通常のカップSVGを画像セットに入れても、これらの性質は得られません。シンボルの動作が必要な場合はその手順を使い、必要なテンプレート構造を保持します。
各プラットフォームの受け渡し形式も個別に確認します。同じアートワークをAndroidにも渡すなら、VectorDrawableの引き継ぎガイドに従います。一方のプラットフォームのインポーターが受け付けても、もう一方での対応は証明されません。
アイコンがPNGでしか存在しない場合
編集可能な元データがなく、PNGが単純なアイコンなら、PerfectVectorのPNGからSVGへのコンバーターで、この手順用のアートワーク候補を準備できます。アイコンに合わせて切り抜き、失われた穴、結合した細部、不要な背景形状をプレビューで確認し、元画像と比較します。採用したSVGをダウンロードし、同じ画像セットと描画モードの確認を行います。
元のベクターがあれば使います。写真や効果の多い画像は、外観を保ちやすければラスターのままにします。ベクター化は形状を準備するもので、Xcodeカタログのコンパイル、リソースバンドルの選択、必要なバリエーションを持つSF Symbolsテンプレートの生成は行いません。
受け渡し前に、カタログ名、original/templateの意図、最小の表示サイズ、再生成に使った元ファイルを記録します。アプリ内で明暗の背景と、対応する外観のバリエーションを試します。ブログのアートワークガイドは、この受け渡し前の元データの準備を扱っています。
よくある質問
SwiftUIはアセットカタログのSVGを使えますか? はい。XcodeはSVG画像アセットに対応しています。通常の画像セットに入れ、Imageで名前付きリソースを読み込みます。任意の実行時SVGへの対応と考えず、デプロイ対象と実際のカタログビルドを確認してください。
SVGが一色になったのはなぜですか? 描画モードを確認します。template描画は見える画像を前景色のシルエットとして使います。元の色の違いが必要ならoriginal描画を使います。
ImageはWeb URLからSVGを読み込めますか? 名前付きImageイニシャライザーはリソースの検索であり、URLによるSVGパーサーではありません。実行時SVGには、実際の入力で検証した適切な描画と読み込みの手順が必要です。
SVG画像セットは独自のSF Symbolと同じですか? いいえ。独自のシンボルは、必要な構造、バリエーション、位置合わせ情報、検証を持つテンプレートを使います。通常のSVG画像セットは自動でそれらの性質を提供しません。
参考資料
- Apple — Xcode 12リリースノート — SVG画像アセット対応と、ベクター保持の対象バージョン。
- Apple — アセットカタログによるアセット管理 — アセットセット、インポート欄、バリエーション。
- Apple — Image init(_:bundle:) — 名前付きリソースとバンドルの検索。
- Apple — Image.TemplateRenderingMode — originalとtemplateの描画モード。
- Apple — resizable(capInsets:resizingMode:) — 明示的な画像のサイズ変更動作。
- Apple — scaledToFit() — 縦横比を保持して収める動作。
- Apple — アプリ用の独自のシンボル画像の作成 — 独自のシンボルのテンプレート、バリエーション、検証。
- Exyte — SVGView — SwiftUI用の別のSVG解析と描画ソリューション。
一式を取り込む前に、目的のサイズと色モードで一つのアイコンを確認します。PNGしか残っていなければ、SVG候補を準備し、穴と背景を確認して、ビルドしたアプリで採用ファイルを検証してください。

