Posts SwiftUI systemVariantでSF Symbolsをちょっとだけ楽に扱う

systemVariantでSF Symbolsをちょっとだけ楽に扱う

はじめに

先日、symbolVariantというViewModifierを知りました。 これまで、冗長に感じていたSF Symbolsの出し分けを簡潔に記載できそうです。 備忘録としてこちらにまとめておきます。 公式ドキュメントはこちらです

SymbolVariantとは

SF Symbolsを利用する際、.で接続する形で、派生のシンボルを使うことができます 例えば、airplaneというシンボルをairplane.circleと派生させることが可能です。

struct ContentView: View {
	var body: some View {
		Image(systemName: "airplane.circle")
	}
} 

上記のコードは、symbolVariantモディファイアを利用した以下のコードと等価です

struct ContentView: View {
	var body: some View {
		Image(systemName: "airplane")
			.symbolVariant(.circle)
	}
}

つまり、symbolVariantモディファイアを使えば、派生系のシンボルの指定をモディファイアに任せることができます!

SymbolVariantのメリット

symbolVariantモディファイアを利用することで、いくつかのメリットが得られます

条件によるSFSymbolsの出し分けが楽になる

次のViewをみてください。 SF Symbolsをボタンのlabelとして利用しています

struct ContentView: View {
	@State var isOn = false
	
	var body: some View {
		Button(
			action: { isOn.toggle() },
			label: {
				Image(systemName: isOn ? "star.fill" : "star.slash")
			}
		) 
	}
}

このように条件によってSF Symbolsを派生させる場合には、symbolVariantモディファイアを利用すると簡単です。

struct ContentView: View {
	@State var isOn = false
	
	var body: some View {
		Button(
			action: { isOn.toggle() },
			label: { 
				Image(systemName: "star")
					.symbolVariant(isOn ? .fill : .slash)
			}
		)
	}
}

派生部分を切り替えていることがわかりやすくなりました! 因みに、symbolVariant(.none)を利用することで、派生のシンボルを利用しないことを明示的に示すことも可能です!

SF Symbolsの派生をまとめて、複数反映できる

複数のSF Symbolsにまとめて反映したり、複数反映したりもできます

struct ContentView: View {
	@State var isOn = false
	
	var body: some View {
		VStack {
			Image(systemName: "airplane")
			Image(systemName: "star")
		}
		.symbolVariant(.fill)
	}
}

デザインの統一感を出しやすくなるかもしれませんね

タイプセーフになる

symbolVariantモディファイアの引数は、SymbolVariantsという型になっています。 enumで定義されているため、タイプセーフに扱うことが可能です。 Xcode16.4.0時点では、以下を利用できます。

  • none
  • circle
  • square
  • rectangle
  • fill
  • slash

利用できない場合も安全

派生は全てのSF Symbolsに存在するわけではありません。 例えば、figure.walkにはfigure.walk.fillfigure.walk.slashは存在しません。 では、以下のコードはどのような挙動を示すでしょう?

struct ContentView: View {
	var body: some View {
		Image(systemName: "figure.walk.fill")
	}
}

この場合、該当するSF Symbolsが存在しないため、何も表示されません では、symbolVariantモディファイアを使うとどうでしょう?

struct ContentView: View {
	var body: some View {
		Image(systemName: "figure.walk")
			.symbolVariant(.fill)
	}
}

この場合、figure.walkが表示されます! 派生形が存在しない場合には、モディファイアが適応されていない状態で表示されるため、安全です。 ※ただし、.slashなど、派生の有無で意味が変わってしまう場合には、ユーザーに混乱を与える可能性があるので注意が必要です。

まとめ

symbolVariantモディファイアを利用することで、SF Symbolsの出し分けが少し楽で安全になります。 皆さんも是非利用してみてください! いつかSF Symbolsの呼び出し自体もOSSなしにタイプセーフにできるといいなぁ。