ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
Springsでアニメーション生成
アニメーションでアプリに命を吹き込む方法を探りましょう。Springsを活用した素晴らしいアニメーションの作り方や、アプリでの活用方法をご紹介します。
関連する章
- 1:36 - Why springs
- 8:33 - How springs work
- 17:29 - How to use springs
リソース
関連ビデオ
WWDC23
-
ダウンロード
♪ ♪
こんにちはJacobです 私たちが構築するUIは変化と動きのある よりダイナミックなものに 進化し続けています ユーザーにも好評です インターフェイスがより生き生きとし 何が起きているのか理解しやすくなり UIとのインタラクションに 楽しさをもたらします
このようなダイナミックインタラクションは さまざまな要素の組み合わせで実現します あるシーンから別のシーンに移動する トランジション デバイスと直接やりとりをする ジェスチャー そして アニメーションは スクリーン上で オブジェクトを動かしたり 成長させたり その視覚的特性を変化させたりします これらすべてが連動して 流動的で インタラクティブなUI作りに役立ちます 今日は優れたアニメーションの 構築について深く知りましょう アニメーションの違いは微妙なものですが 効果的なアニメーションは ユーザーも実感できます 今回紹介する方法は アプリのアニメーションを エレガントで自然にします 今日は楽しいツールを1つだけ紹介します パワフルで汎用性が高い springsです! まずspringがアニメーションに 適している理由を説明します そしてspringの仕組みについて 詳しく説明します そして最後にアプリでの springの使い方についてお話します ではなぜアニメーションに springが有用なのでしょうか? その答えとして優れたアニメーションとは 何かについてまず説明します 単純なトグルのあるアニメーションで 見ていきましょう このトグルに注目してみましょう
アニメーションを使う理由は いくつかありますが 最も重要なことのひとつは 連続性を表現することです オブジェクトがある場所で始まり 突然別の場所に現れると 違和感があり 時には混乱も招きます もっと自然なのは オブジェクトがある場所から 次の場所に移動する動きです
しかしそれは位置の問題だけではありません オブジェクトの速度が突然変わると それも不自然です 例えばこのトグルのノブは 始まりと終わりに 速度のジャンプがあり不自然です つまり目指したいのはアニメーションの 位置と速度を安定させることです いくつかのアニメーションタイプを見て その要件を見てみましょう このトグルは 完全なアニメーションの良い例ですが ノブの動きだけに焦点を当てたいので 1つのアニメーションだけで見ていきます まずイーズインと イーズアウトから見ていきます これはベジェ曲線アニメーションの一種で 曲線とdurationの組み合わせで 動きを定義しています このオブジェクトの動きを見ると 急激なジャンプがあるようには 感じられません これを確かめるために このアニメーションの 動きのチャートも見てみましょう
このチャートのいくつかを見ていくので それが何を示しているかを説明します 横軸は時間を示し 下の線はアニメーションの初期位置 上の線は目標位置を示しています そしてアニメーションを 繰り返し再生することで この曲線を繰り返し進んでいきます ではもう一度アニメーションを始めてみます チャートの曲線にジャンプがなく 位置が一定していることに注目してください 速度も表示されるように チャートを更新すると 速度にもジャンプがないことが確認できます つまり速度も一定です
リニアアニメーションの動きを見てみると アニメーションの開始と終了時に 鋭い角があり 速度にジャンプがあります リニアアニメーションは 特殊ツールとして便利な場合もありますが 例えば 回転を繰り返すインジケーターなど その他では使用に注意が必要です 特に移動がある動作では このような非物理的な動きに注意しましょう
次にspringアニメーションの連続性を チェックしてみましょう 私たちが望んでいるように これは位置と速度も継続しています 今のところイーズイン・アウトと springアニメーションが最良に見えますが 今まではアニメーションが 静止位置から始まる場合のみを 見てきました ジェスチャーとアニメーションを 一緒に使うとどうなるか 見てみましょう 可動式のノブをiPad上に反映し 指でドラッグしてみましょう
この2つの位置のどちらかに ドロップすることができます しかし中間点でジェスチャーを終了させ ノブを片側に投げ出すこともできます
イーズイン・アウトのアニメーションでは 最後までアニメーションしますが ジェスチャーが終わると 突然動きが止まります
このタイプのアニメーションは 指定されたカーブを描くだけなので 初速を定義する方法がありません これは 2次元の任意の位置に ノブをドラッグできるようにすると さらに悪化します
今度はspringアニメーションで 試してみましょう springはどのような初速度でも 開始できるので ジェスチャーが終わった途端に アニメーションが始まるという 自然な印象が得られます
これは2次元のドラッグにも効果的です
SwiftUIは ジェスチャーのプロパティ変更時に いつでも自動的に速度を追跡するので 余分な作業なく この動作を得ることができます つまりspringsは 静的な場合と初速がある場合の両方で 連続性を維持する 唯一のアニメーションのタイプです springの次の利点はその動きの形状です
springの動きと聞くと このようなものを 思い浮かべるかもしれません
しかしspringのアニメーションは 弾むだけではありません 確かにspringには弾みがあり 素晴らしいツールですが springを使う主な理由は他にあります 後ほど 弾みのあるspringが有用な例も 説明しますが 弾みのないspringも 素晴らしいものです! 弾みのないspringはiOSの あらゆるアニメーションで使用されています では弾み以外のspringの動きの 魅力は何でしょうか? もう一度 シンプルなspringアニメーションと その終わり方を見てみましょう 非常にゆっくりと徐々に静止していますね オブジェクトが 突然終了する瞬間はありません これは私たちが想定する 動いている物体の止まり方に近いです そしてこのバージョンが より自然に感じられるのには理由があります springアニメーションが 物理的な実世界の バネを取り付けた物体の動きを 参照しているので 私たちの目には 自然で信憑性のあるものに見えるのです springを使ったアニメーションは プロパティによって 終了するタイミングが 異なるというのは本当です Timing curveのアニメーションに 慣れていると奇妙に思うかもしれません すべてのアニメーションが同時に開始し 同時に停止するのがよいでしょうか 答えはノーです! アニメーションは私たちが慣れ親しんでいる 現実世界の動きに似せたいのです そして一般的にこれらのアニメーションは 摩擦によって減速されるため それぞれのタイミングで 開始したり停止したりします 実際マルチプロパティアニメーションでは 細かく設定すると良い場合もあります これはiOSで アプリが起動するアニメーションです 一見すると 1つの均一なアニメーションに見えますが アニメーションをスローにして見ると 異なるspringと 異なる開始時間と終了時間が組み合わさって 驚くほど自然なアニメーションを 形成しているのが分かります
springのアニメーションにおける 最適性を理解したところで springの仕組みと最適な使い方について 詳しく見ていきましょう springアニメーションを使用するとき 私たちはバネに取り付けられた 物体の動きを参照しています 物理学に戻ると この動きは 3つのプロパティによって定義されます 物体のmass springのstiffness そしてdampingは 周囲から物体にかかる 摩擦の大きさを表します 次にアニメーションの初期位置を 物体の初期位置として使用し アニメーションの目標位置は バネで引っ張られた先の物体の静止位置を 定義するために使用します その後オブジェクトをリリースして アニメーションを開始します springシステム定義用のプロパティは 発生するモーションのタイプを決定し それらを変更すると アニメーションも変更されます
そのため springアニメーションを作成する場合 massとstiffnessそしてdampingに 同じプロパティを使用して springの種類を設定することができます これらは 物理的なシステムのモデル化には 自然な方法ですが springアニメーションの定義としては 直感的ではありません 質量を持つ実際の物体も 剛性を持つばねもありませんし カーブを変えるためにこれらの値を作るのは 容易ではありません そのため私たちは より理解しやすく作業しやすい springの新しい設定方法を 改良してきました 2つのパラメータ durationとbounceを使います ご想像どおり durationを長くすると アニメーションが長くなります bounceを増やすと アニメーションに跳ね返りが追加されます これらはAppleのデザインと エンジニアリング全体に採用されています そのためspring対応のすべての フレームワークで採用されています
これらspringパラメーターで 様々なタイプの形状のカーブを 見ることができます bounceが0より大きいと 目標を超えて跳ねるspringになります bounceが0だと 長く伸びて徐々に ターゲットに向かう滑らかな曲線になります そしてもうひとつタイプがあります 一般的ではありませんが bounce値がネガティブの場合も 徐々にターゲットに近づくspringで バウンス0よりも少し平坦です バネの物理学ではこれらを 不足減衰 臨界減衰 そして 過減衰といいます でも私は 弾みやすい 滑らか 平ら と区別しています お気づきかもしれませんが これらのbounce値は パーセンテージなので 弾むspringは バウンス値が100%までで 平らなspringはバウンス値が 0からマイナス100%です springについて 更に掘り下げてみましょう springは時に複雑で 理解が難しいように思われるかもしれません しかし分解して見ていくと実は いくつかの単純なことが 組み合わさっているだけなのです 私の場合 これら曲線の背後にある 数学を理解することで springがより身近なものになったので それを共有したいと思います しかし数学は頭を 混乱させるだけだという方も ご心配なく この計算はすべて私たちが行います
では弾む曲線から始めましょう このspringのオーバーシュートが もっと複雑なサイン波やコサイン波のように 振動することに気づくかもしれません このバウンスを最大値の100%まで上げると まさにコサイン波の挙動になり 前後に振動していることがわかります
これを物理的に解釈すると バネには 摩擦が作用しないので 減速することなく永遠に振動し続け 目標位置には 到達しないということになります 予想通りこれも数学的にはとても簡単です コサイン曲線で 時間が持続時間で割っているだけです だからこのバウンス値の持続時間は 曲線の周期に正確に対応します バウンスを小さくすることは物理的には バネに摩擦や減衰を加えることと同じで バネの動きを遅くします そしてまだ振動は続きます 実際先ほどのコサイン曲線がまだあり 上に重ねて描けばもっとはっきりします これは前と同じ式で 定数が違って少し横にずれているだけです これで曲線の跳ね返りは説明できますが 明らかに何かが足りません 元の曲線では振動の大きさが 時間とともに小さくなり つまり減衰しています それが欠けている部分です この追加曲線は指数関数的減衰した曲線です そして動きの最後の 徐々に静止する感覚を与える部分です
複雑な曲線に見えたのは この2種類でできており 減衰コサイン波 または サイン波と呼ばれます でもチャートをよく見ると ちょっと不思議なことがあります なぜコサイン曲線の最初に 凹みがあるのでしょうか? これは先ほど説明したことと関係があります 速度の保持です この基本ケースでは最初の速度0を保持する 必要があるのです つまり2つの曲線の合わせた速度は 0付近で平坦になるはずです しかし減衰曲線は 上向きの傾きで始まっています もしコサイン曲線が平坦に始まったら 初速も上向きになります そのため コサイン曲線は 減衰と相殺して スタートを平坦にするために 下向きにスタートするのです このようにコサイン曲線のシフトと スケールを使い分けることで springは どんな初速にも対応できるのです
この初期速度は先ほど説明したように ジェスチャー終了時にアニメーションに 引き継ぐ速度から得ることができます 初速が得られる場所はもうひとつあります iPadで見てみましょう ここではタップしてノブを動かし ノブの画像を薄めに表示することができます 分かりやすいように ゆっくりとしたspringを使います アニメーションがまだ終わっていない間に 新しいアニメーションが始まり 新しい目標値に変わることがあります そのような場合 springアニメーションは リターゲットされた時の速度を 新しい目的地へ向かう初速として使用します これによりインタラプトがスムーズで 自然に感じられるようになります
これが速度保持と弾むspringの仕組みです bounceを小さくしていくと 振動はどんどん離れていき バウンスが0に到達すると 振動は完全になくなり 減衰によって乗算された直線だけが 下へ下へと遠ざかっていきます つまりこの方程式はもっとシンプルなのです 線の基本方程式が必要なだけで それに同じ指数を掛けると 結果の曲線が得られます
負のバウンスを持つ扁平曲線の動きも よく似ていますが直線の代わりに 2つの指数関数を足したものを使います これはあまり一般的ではありませんが 指数減衰だけで表されるため スクロールビューで起こるような 速度減衰のモデリングに便利です
アニメーションにspringを使用する際に こう思うかもしれません springアニメーションが実際に 終了するまでの時間はどれくらい? これまで見てきたように これは絶妙な疑問です springの指数関数的な減衰は 技術的には永遠に動き続けます 動きが小さくなるだけです もちろんspringアニメーションを 永続させたくないので ある時点で削除する必要があります UIに顕著な変化を与えなくなったときです springアニメーションが 十分に完了して消せるまでの時間を settlingDurationと呼びます これはspringを設定する durationパラメータとは 異なります settlingDurationは 様々な要因に左右されるため 予測不可能な場合がありますが durationパラメータは知覚的であり 他のパラメータが変化しても 予測可能で動き回らないように選択されます その予測不可能な性質のため ユーザが見る変更については settlingDurationは勧めません springがほとんど完了したときに UIを変更したい場合 perceptual durationを使った SwiftUIの新しいcompletionHandlerの サポートを使うことができます springの機能を理解したので コード内での使用方法を見ていきましょう springはアニメーションのための 素晴らしいツールなので SwiftUIのデフォルトとなっており withAnimationを呼び出すだけで 始められます アニメーションのためにspringを 明示的に使用することも簡単になりました いくつかのspringプリセットを iOSで使われている springの値に基づいて組み込みました どのようなパラメータを使用するか悩んだら これらを使用すると良いでしょう
アニメーションが必要なところに プリセットを 直接コード入力できます しかし必要なコンテキストに 合わせることが重要なので プリセットは変更を加える スタート要素として使うこともできます プリセットを使用して持続時間を指定したり バウンス量を相対的に指定して 増減することができます これらのプリセットはアプリに springを導入する最適な方法です さらに上を目指すのであれば .springアニメーションを使って 完全にカスタマイズもできます これによりspringの持続時間と bounceを完全に指定できます バウンス値の範囲は-1.0から1.0です 同じパラメータを使用して UIKitやCore Animationで springアニメーションを 作成することもできます
さらに先に進みたいのであれば 別の新しいspringツールがあります SwiftUIにSpringモデル型を追加し パラメータを含むspringの表現を 作成できるようにしました これにより パラメータを指定する異なる方法の間で パラメータをプログラムで変換できます springアニメーションとしてMassや stiffnessやdampingを設定し 直接使用することもできます しかし本当に自分で変換を行いたい場合は 次の方程式でbounceと持続時間の値を Massやstiffnessや dampingに変換できます パラメータを変換するだけでなく springモデルを使用して独自の 高度なspring動作構築もできます springのメソッドを呼び出すことで 組み込まれたspring評価計算を 自分で行えます 例えばvalueを呼び出して springの位置を取得できます ターゲットを与えるだけです つまり springが向かっている方向と 評価したい時間を指定するだけです 同じ入力を velocityメソッドで使用することで springの速度を評価できます 独自のコードで 簡単にspringを使うことができ シミュレーションや この動画に出てきたような グラフの値を取得するのに便利です 独自のアニメーション作成もできます springモデルを呼び出して 入力や出力を変更して カスタマイズできます カスタムアニメーションについては 「Explore SwiftUI animation」を ご視聴ください 最後に説明するのは springに使用する パラメータの選び方についてです あなたのアニメーションに 最適な値を選ぶには あなたが好きなテンポのduration値を 見つけると良いです それが決まったらbounce量を調整し アニメーションの雰囲気や個性を決めます bounce値の違いによって 質感が変わることがわかるでしょう 0のbounceは滑らかで緩やかな変化です 15%位の小さなbounceは あまり弾みはないですが 余韻は少し勢いがあるように感じます 30%など値が大きくなると 顕著な弾みが感じられ さらに踏み込めば かなり極端な弾みになります しかし0.4より高い値を使用すると UI要素としては 大げさかもしれないので慎重になるべきです では実際にどの値を使うべきでしょうか? わからない場合は 0のspringを使用しましょう これはデフォルト値でもあります これにより 最も汎用性の高いspringができます もう少し遊び心を持たせたい場合は bounceを追加できます bounceはアニメーションを より物理的に感じさせたい場合にも良いです 例えなジェスチャーの最後などです そして留意すべきことは一貫性です あなたのアプリの個性について考えましょう 真面目なのか遊び心があるのか リラックスした感じか急かしい感じなのか UIのフィーリングと一致する spring値を選択しましょう 以上 アニメーションでの springの説明でした 弾まないspringでも 素晴らしいアニメーションが作れます そのまま使える新しい springのプリセットもありますが 必要な場合はdurationとbounceを使って カスタマイズもできます 大事なのは今回知った springが持つユニークな長所を 活用して あなたのアプリが流動的で 楽しいものになりますように ありがとう ♪ ♪
-
-
18:00 - Spring Preset
withAnimation(.snappy) { // Changes }
-
18:15 - Spring Preset with Custom Duration
withAnimation(.snappy(duration: 0.4)) { // Changes }
-
18:21 - Spring Preset with Custom Bounce
withAnimation(.snappy(extraBounce: 0.1)) { // Changes }
-
18:37 - Custom Spring
withAnimation(.spring(duration: 0.6, bounce: 0.2)) { // Changes } // UIKit UIView.animate(duration: 0.6, bounce: 0.2) { // Changes } // Core Animation let animation = CASpringAnimation(perceptualDuration: 0.6, bounce: 0.2)
-
18:57 - Spring Model
let mySpring = Spring(duration: 0.5, bounce: 0.2) let (mass, stiffness, damping) = (mySpring.mass, mySpring.stiffness, mySpring.damping)
-
19:16 - Spring Model Animation
let otherSpring = Spring(mass: 1, stiffness: 100, damping: 10) withAnimation(.spring(otherSpring)) { // Changes }
-
19:26 - Spring Parameter Conversion
mass = 1 stiffness = (2π ÷ duration)^2 damping = 1 - 4π × bounce ÷ duration, bounce ≥ 0 4π ÷ (duration + 4π × bounce), bounce < 0
-
19:35 - Evaluating Spring Model
let mySpring = Spring(duration: 0.4, bounce: 0.2) let value = mySpring.value(target: 1, time: time) let velocity = mySpring.velocity(target: 1, time: time)
-
20:15 - Custom Spring Animation
func animate<V: VectorArithmetic>( value: V, time: Double, context: inout AnimationContext<V> ) -> V? { spring.value( target: value, initialVelocity: context.initialVelocity, time: effectiveTime(time: time, context: context)) }
-
20:34 - Spring with No Bounce
withAnimation(.spring(duration: 0.5)) { isActive.toggle() }
-
21:07 - Spring with Small Bounce
withAnimation(.spring(duration: 0.5, bounce: 0.15)) { isActive.toggle() }
-
21:14 - Spring with Large Bounce
withAnimation(.spring(duration: 0.5, bounce: 0.3)) { isActive.toggle() }
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。