🚗

SwiftUIでのイージングとSpring Animationはどう使い分ける?最適な方法で心地よいアニメーションを目指そう!

2023/06/14に公開

こんにちは!テラーノベルでiOS/Android/Webとフロントエンド周りを担当している @kazutoyoです!

WWDC 2023でのPlatforms State of the Unionで話されていたように、SwiftUIのアニメーションのデフォルトがSpringに変更され、APIもシンプルなものが提供される予定です。

また、SpringアニメーションについてのAnimate with springsを元に、今回はイージングとSpringをつかったアニメーションについてお話します。

アニメーションとイージング

アニメーションは、開始から終了までの時間と値の変化で決まります。

この時間変化における値は、利用するイージング関数により変わります。
以下にいくつか代表的なイージングの種類を説明します。

Linear

Linear関数は時間に対して等速に変化するイージングです。


Apple ドキュメントより

アニメーションとして見ると以下のようで、機械的に感じるかと思います。
わざと機械的に見せたいような場合以外、そこまで利用する機会は多くないかなと思います。

EaseIn

EaseIn関数は時間経過とともに、変化が大きくなるイージングです。

Apple ドキュメントより

アニメーションとしてみると次のような感じです。
アニメーションに勢いを持たせるときに利用することが考えられますが、個人的にはそれほど出番は多くないと考えます。

EaseOut

EaseOut関数はEaseIn関数の逆に、徐々にゆっくりとした変化となるイージングです。

Apple ドキュメントより

アニメーションを見ると次のとおりです。
余韻のあるアニメーションで、個人的にもよく利用するイージングとなっています。
困ったらEaseOut!

EaseInOut

EaseInOut関数は最初と最後の変化量が少ないイージングです。

Apple ドキュメントより

アニメーションを見ると次のとおりです。
こちらの車の移動アニメーションのように、要素が移動するときのアニメーションとしては一番適していそうなアニメーションですね!

Springアニメーション

イージングでのデメリット

先に述べたように、最適なイージングを選ぶことで状態の変化をわかりやすくユーザに伝えることができます。
ただし、イージングは現在の値から指定した値まで一定時間行うアニメーションのため、ジェスチャーなどユーザがインタラクティブに行うアニメーションには適さないことがあります。

例えば、以下のようにドラッグ&ドロップを行うようなときです。
イージングでのアニメーションは決められた値から値へと時間で変化するため、初速を表現することが出来ません。
そのため、アニメーション開始時に一度動きが止まってから始まるように感じます。(動画では分かりづらいですが…)

Springアニメーションのとき

SwiftUIを利用している場合、ジェスチャーでプロパティを変更しているときは自動的に速度を追跡しているそうです。
そして、Springアニメーションを開始時にそのときの初速を使ってアニメーションをスムーズに行うことができます。

Springアニメーションと聞くと、弾んだりする少し大げさなアニメーションなのかな?と思うかもしれません。
確かにそのようなアニメーションでも利用できますが、bounce(弾み)のないアニメーションとしても利用することが出来ます。
(そして、これらはiOSのモーダルやアプリの起動時など、様々な部分で利用されています。)

Springアニメーションについて

Springアニメーションを理解するためには、現実世界のバネに置き換えると理解がしやすいと思います。
こちらのサイトはreact-springのためのビジュアライザーですが、基本的にバネについての考え方は同じため参考になるかと思います。
https://react-spring-visualizer.com/

先程のドラッグ&ドロップのアニメーションの例では、その物体と終点にバネが繋がっており、指を離したときにバネの力を利用して終点へと物体が引き寄せられるといったイメージを持てると思います。

Spring AnimationとPreset

Xcode 15から利用できる、SwiftUIでのSpring AnimationのPresetに以下の3つが提供されています。

見比べてみると次のような感じです。
基本的にはsmoothで良いかと思いますが、アプリの世界観に合うようなSpringのアニメーションを適切に選びましょう!

smooth snappy bouncy
bounceなし ややbounce bounceあり

また、これらのPresetには durationextraBounce を設定が可能なため、これらを使って微調整も可能です。

withAnimation(.snappy(duration: 0.6, bounce: 0.2)) {
  // Changes
}

また、Presetを利用せずにカスタムなSpringアニメーションを作成も可能です。

withAnimation(.spring(duration: 0.5, bounce: 0.15)) {
  // Changes
}

UIKitでのSpring Animation

iOS 17からとなりますが、UIKitでもdurationとbounceの調整が簡単になった animate(springDuration:bounce:initialSpringVelocity:delay:options:animations:completion:) メソッドが追加されました。

https://developer.apple.com/videos/play/wwdc2023/10055/?time=1383

UIView.animate(springDuration: 0.5, bounce: 0.0) {
  // Changes
}

iOS 17+なのですぐには利用しづらいですが、UIKitでもbounceなしSpringを簡単に実装できるのは良いですね! 🎉

まとめ

新しいAPI、Presetが登場したことにより、SwiftUI/UIKitでもSpringアニメーションが利用しやすくなりました。

イージングやSpringなどを利用する場面により適切に使い分け、心地よいアニメーションを作っていきましょう! 💪

テラーノベル テックブログ

Discussion