SwiftUIがSF Symbols Artを進化させる。try! Swift Tokyo 2024でのトークの裏側
日本最大級のSwiftのカンファレンス try! Swift Tokyo 2024で登壇してきました。
try! Swiftは、世界中からSwift愛好者が集結し、日頃のSwiftの知識やスキルを披露し共有するカンファレンスです。
オープニングを始まる前に撮影したのですが、人が沢山いて緊張感を隠しきれませんでした。(Apple Watchからもアラートが表示される)
786名の方が今回のカンファレンスに参加されると知り、鼓動が更に速くなります、、
登壇内容
SF Symbolsの芸術的世界:限りない可能性を解き放つというテーマで登壇させていただきました。かれこれ3年近くSF Symbolsの魅力に囚われ、研究しているSF Symbols Artについての発表でした。
今回は英語での登壇でしたが、日本人の方も海外の方も楽しんでもらえたようなのでとても良かったです。
昨年11月のアルゼンチン登壇での反省点を生かすべく、色々と工夫と練習をしたのでそれ成果を出せた?ようなので一安心です。
発表資料
アート作品
アップロードした資料がPDFでアニメーションが表示されない為、いくつか作品をピックアップして載せます。
Nosebleed
Arm hair
Pants
Fireworks
その他の作品は、SFSymbolsArtCollectionをビルドすると確認できます。
認定証
今回は講習を受けてくれた方(発表を聞いてくれた方)に認定証を渡したいと思い、Apple Walletに登録されるPassを用意しました。
SwiftUIがSF Symbolsを進化させる
実は今回の登壇で伝えたかった裏テーマはSwiftUIがSF Symbolsを進化されるというポイントでした。しかし、今回は5分~10分という枠で伝える必要があり、資料を削り取っていく中でコードに関する部分は削り取らざるを得ない状態になってしまいました。
この場を借りて、SF SymbolsがSwiftUIと共にどう進化してきたかお伝えしていきます。
iOS 15
SymbolRenderingMode
が追加されました。
SymbolRenderingMode
この機能を使うことでよりSF Symbolsを華やかにでき、表現をより魅力的なものにすることができます。.symbolRenderingMode
モディファイアを使用することで簡単に使用できます。
import SwiftUI struct ContentView: View { var body: some View { VStack(spacing: 32) { VStack { Image(systemName: "cloud.heavyrain.fill") .font(.system(size: 60)) .symbolRenderingMode(.monochrome) .foregroundStyle(.gray) Text("monochrome") } VStack { Image(systemName: "cloud.heavyrain.fill") .font(.system(size: 60)) .symbolRenderingMode(.hierarchical) .foregroundStyle(.gray) Text("hierarchical") } VStack { Image(systemName: "cloud.heavyrain.fill") .font(.system(size: 60)) .symbolRenderingMode(.palette) .foregroundStyle(.gray, .blue) Text("palette") } VStack { Image(systemName: "cloud.heavyrain.fill") .font(.system(size: 60)) .symbolRenderingMode(.multicolor) .foregroundStyle(.gray) Text("multicolor") } } .frame(maxWidth: .infinity, maxHeight: .infinity) .background(.cyan.opacity(0.3)) } }
それぞれのSymbolRenderingMode
の見え方はこのようになります。
SymbolRenderingMode | 概要 |
---|---|
monochrome | 単色のレイヤーとしてレンダリング |
hierarchical | 設定した色から異なる不透明度で複数のレイヤーとしてレンダリング |
palette | 設定した複数の色から複数のレイヤーとしてレンダリング |
multicolor | 独自の色を持っている場合は、その色が適用されてレンダリング |
iOS 16
iOS 16からinit(systemName:variableValue:)
を使用できるようになり、可変カラーをシンボルに適用できるようになりました。
しかし、全てのシンボルに可変カラーを使用できるわけではありません。
可変カラー適用のシンボルについては、SF Symbolsのアプリの可変カラーを選択すると確認できます。
variableValue
の値を変化させることで、シンボルの見た目を変化させることができます。
struct ContentView: View { @State private var value: Double = 0 var body: some View { VStack { Image(systemName: "rainbow", variableValue: value) .symbolRenderingMode(.multicolor) .font(.system(size: 100)) Slider(value: $value) .padding() } } }
iOS 17
SymbolEffect
が追加され、シンボルにプレセンテーションエフェクトを適用できるようになりました。
SymbolEffect
SymbolEffect
で使用できるエフェクトは8種類あります。
SymbolEffect | 概要 |
---|---|
appear | シンボルの画像のレイヤーを個別にまたはまとめて表示するアニメーション |
automatic | シンボルの画像にデフォルトのアニメーションをコンテキストに応じて適用するトランジション |
bounce | シンボルの画像のレイヤーに一時的なスケーリング効果、またはバウンスを適用するアニメーション |
disappear | シンボルの画像のレイヤーを個別にまたはまとめて消去するアニメーション |
pulse | シンボルの画像のいくつかまたはすべてのレイヤーの不透明度をフェードするアニメーション |
replace | 1つのシンボルベースの画像のレイヤーを別のものと置き換えるアニメーション |
scale | シンボルの画像のレイヤーを個別にまたはまとめてスケーリングするアニメーション |
variableColor | シンボルベースの画像の可変レイヤーの不透明度を繰り返しシーケンスで置き換えるアニメーション |
今回はbounce
の使用例を紹介します。
bounce
struct ContentView: View { @State private var counter: Int = 0 var body: some View { Image(systemName: "heart.fill") .symbolRenderingMode(.multicolor) .font(.system(size: 100)) .symbolEffect(.bounce, value: counter) .onAppear { Timer.scheduledTimer(withTimeInterval: 0.6, repeats: true) { timer in counter += 1 if counter > 10 { timer.invalidate() } } } } }
今回はTimer
を使用してcounter
をカウントアップさせ、counter
の値が切り替わる度にbounce
のエフェクトが発生するようにしました。
KeyframeAnimator
また、iOS 17からKeyframeAnimator
が使用できるようになり、これによって気軽に細かいアニメーションを行うことができるようになりました。これはSF SymbolsのImage
のみに適用されるものではなく、View
に対して使用することができます。
まずはアニメーションを行うためのAnimationValue
を定義します。
struct AnimationValue { var fontSize: CGFloat var positionX: CGFloat var positionY: CGFloat }
そして、keyframeAnimator
モディファイアを使用し、初期値と各KeyFrame毎にどの時間でどのような値に変化させたいかを設定します。
struct ContentView: View { @State private var isAnimating = false var body: some View { ZStack(alignment: .bottom) { Image(systemName: "eyeglasses") .keyframeAnimator(initialValue: AnimationValue(fontSize: 30, positionX: 40, positionY: 100), trigger: isAnimating) { content, value in content .font(.system(size: value.fontSize)) .position(x: value.positionX, y: value.positionY) } keyframes: { _ in KeyframeTrack(\.fontSize) { CubicKeyframe(100, duration: 2) } KeyframeTrack(\.positionX) { CubicKeyframe(200, duration: 2) } KeyframeTrack(\.positionY) { CubicKeyframe(100, duration: 2) } } Image(systemName: "tirepressure") .keyframeAnimator(initialValue: AnimationValue(fontSize: 30, positionX: 100, positionY: 100), trigger: isAnimating) { content, value in content .font(.system(size: value.fontSize)) .position(x: value.positionX, y: value.positionY) } keyframes: { _ in KeyframeTrack(\.fontSize) { CubicKeyframe(100, duration: 2) } KeyframeTrack(\.positionX) { CubicKeyframe(200, duration: 2) } KeyframeTrack(\.positionY) { CubicKeyframe(200, duration: 2) } } Image(systemName: "tirepressure") .keyframeAnimator(initialValue: AnimationValue(fontSize: 30, positionX: 100, positionY: 100), trigger: isAnimating) { content, value in content .font(.system(size: value.fontSize)) .position(x: value.positionX, y: value.positionY) } keyframes: { _ in KeyframeTrack(\.fontSize) { CubicKeyframe(100, duration: 2) } KeyframeTrack(\.positionX) { CubicKeyframe(200, duration: 2) } KeyframeTrack(\.positionY) { CubicKeyframe(200, duration: 2) } } Image(systemName: "light.panel") .keyframeAnimator(initialValue: AnimationValue(fontSize: 30, positionX: 160, positionY: 100), trigger: isAnimating) { content, value in content .font(.system(size: value.fontSize)) .position(x: value.positionX, y: value.positionY) } keyframes: { _ in KeyframeTrack(\.fontSize) { CubicKeyframe(100, duration: 2) } KeyframeTrack(\.positionX) { CubicKeyframe(200, duration: 2) } KeyframeTrack(\.positionY) { CubicKeyframe(320, duration: 2) } } Button("Start animating") { isAnimating = true } } .frame(maxWidth: .infinity, maxHeight: .infinity) } }
上記の例だとこのように動作します。
アニメーションを簡単に追加できるようになり、SF Symbols Artの魅了が更に高まりました。
おわりに
駆け足になってしまいましたが、SF Symbolsの進化について説明させていただきました。
こう見てみると、SF Symbolsで使用できる機能が一年に一回は追加されているのでこれからも目を離せませんね。
引き続き、SF Symbolsの進化を追っていきたいと思います!
try! Swiftはまだまだ続きます。残りも楽しんでいきます!