UIKitとUIViewを使用してビューでiOSアニメーションを実行する
公開: 2022-03-10私は10年以上iOS開発者であり、iOSでアニメーションを実行するためのすべての可能な方法を統合した記事をめったに見たことがありません。 この記事は、iOSアニメーションの入門書であり、同じことを行うさまざまな方法を網羅的にカバーすることを目的としています。
トピックの広さを考えると、かなり高いレベルで各部分を簡潔にカバーします。 目標は、iOSアプリにアニメーションを追加するための一連の選択肢を読者に提供することです。
iOSに関連するトピックから始める前に、アニメーションの速度について簡単に見てみましょう。
60FPSでのアニメーション
通常、ビデオでは、各フレームは画像で表され、フレームレートによって、シーケンスで反転される画像の数が決まります。 これは「1秒あたりのフレーム数」またはFPSと呼ばれます。
FPSは、1秒間に反転する静止画像の数を決定します。これは、文字通り、画像/フレームの数が多いほど、ビデオに表示される詳細/情報が増えることを意味します。 これはアニメーションにも当てはまります。
FPSは通常、アニメーションの品質を決定するために使用されます。 優れたアニメーションは60fps以上で実行する必要があるという一般的な意見があります。60fps未満のものは少し気分が悪くなります。
30FPSと60FPSの違いを見たいですか? これをチェックして!
違いに気づきましたか? 人間の目は、より低いfpsで確実にジッターを感じることができます。 したがって、作成するアニメーションが60FPS以上で実行されるという基本ルールに準拠していることを確認することは常に良い習慣です。 これにより、よりリアルで生き生きとした感じになります。
FPSを見てきたので、アニメーションを実行する方法を提供するさまざまなコアiOSフレームワークについて詳しく見ていきましょう。
コアフレームワーク
このセクションでは、ビューアニメーションの作成に使用できるiOSSDKのフレームワークについて説明します。 それぞれについて簡単に説明し、関連する例を使用して機能セットを説明します。
UIKit / UIViewアニメーション
UIViewは、iOSアプリでコンテンツを表示するすべてのビューの基本クラスです。
UIViewを提供するフレームワークであるUIKitは、開発者が少ない労力でより多くのことを達成するのに便利ないくつかの基本的なアニメーション機能をすでに提供しています。
APIのUIView.animate
は、ブロックベースの構文でプロパティ値を提供することで任意のビューのプロパティを簡単にアニメーション化できるため、ビューをアニメーション化する最も簡単な方法です。
UIKitアニメーションでは、UIVIewのアニメーション化可能なプロパティのみを変更することをお勧めします。そうしないと、アニメーションによってビューが予期しない状態になる可能性があります。
アニメーション(withDuration:アニメーション:完了)
このメソッドは、アニメーション化する必要のあるビューのアニメーション化可能なプロパティの変更のセットであるアニメーション期間を取り込みます。 ビューがアニメーションの実行を終了すると、完了ブロックはコールバックを提供します。
この単一のAPIを使用して、ビューでの移動、スケーリング、回転、フェードなど、ほぼすべての種類のアニメーションを実現できます。
ここで、ボタンサイズの変更をアニメーション化するか、特定のビューを画面にズームインする必要があると考えてください。 UIView.animate
を使用してこれを行う方法は次のとおりです。
let newButtonWidth: CGFloat = 60 UIView.animate(withDuration: 2.0) { //1 self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) //2 self.button.center = self.view.center //3 }
ここで行っていることは次のとおりです。
- ブロック内に記述されているアニメーションの実行時間を表すduration値を渡して
UIView.animate
メソッドを呼び出します。 - アニメーションの最終状態を表すボタンの新しいフレームを設定します。
- ボタンの
center
をスーパービューの中央に設定して、画面の中央に留まるようにします。
上記のアニメーションコードのブロックは、ボタンのフレームが現在のフレームから変化するアニメーションをトリガーする必要があります。
Width = 0, Height = 0
最後のフレームへ:
Width = Height = newButtonWidth
そして、アニメーションは次のようになります。
animateWithDuration
このメソッドは、ビューアニメーションにいくつかの物理動作を追加して、以前のAPIで実行できるすべてのことを実行できるanimateメソッドの拡張に似ています。
たとえば、上記で行ったアニメーションでスプリングダンピング効果を実現する場合、コードは次のようになります。
let newButtonWidth: CGFloat = 60 UIView.animate(withDuration: 1.0, //1 delay: 0.0, //2 usingSpringWithDamping: 0.3, //3 initialSpringVelocity: 1, //4 options: UIView.AnimationOptions.curveEaseInOut, //5 animations: ({ //6 self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) self.button.center = self.view.center }), completion: nil)
使用するパラメータのセットは次のとおりです。
-
duration
コードのブロックを実行する時間を決定するアニメーションの期間を表します。 -
delay
アニメーションの開始前に必要な初期遅延を表します。 -
SpringWithDamping
ビューに動作させたい弾力性のある効果の値を表します。 値は0から1の間でなければなりません。値が小さいほど、ばねの振動が大きくなります。 -
velocity
アニメーションを開始する速度を表します。 -
options
ビューアニメーションに適用するアニメーションカーブのタイプ。 - 最後に、アニメーション化する必要のあるボタンのフレームを設定するコードのブロック。 前のアニメーションと同じです。
そして、上記のアニメーション構成でのアニメーションは次のようになります。
UIViewPropertyAnimator
アニメーションをもう少し制御するために、 UIViewPropertyAnimator
は、アニメーションを一時停止および再開する方法を提供するのに便利です。 カスタムタイミングを設定し、アニメーションをインタラクティブで中断可能にすることができます。 これは、ユーザーアクションとも相互作用できるアニメーションを実行するときに非常に役立ちます。
古典的な「スライドしてロックを解除する」ジェスチャとプレーヤービューの却下/展開アニメーション(ミュージックアプリ内)は、インタラクティブで中断可能なアニメーションの例です。 指でビューの移動を開始してから離すと、ビューが元の位置に戻ります。 または、アニメーション中にビューをキャッチして、指でドラッグし続けることもできます。
以下は、 UIViewPropertyAnimator
を使用してアニメーションを実現する方法の簡単な例です。
let newButtonWidth: CGFloat = 60 let animator = UIViewPropertyAnimator(duration:0.3, curve: .linear) { //1 self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) self.button.center = self.view.center } animator.startAnimation() //2
これが私たちがしていることです:
- 継続時間とアニメーション曲線を渡すことにより、
UIViewProperty
を呼び出します。 - 上記の両方のUIView.animateAPIとは異なり、アニメーションは、自分で指定しない限り、つまり完全なアニメーションプロセス/フローを完全に制御できない限り、開始されません。
ここで、アニメーションをさらに細かく制御したいとします。 たとえば、アニメーションのすべてのフレームを設計および制御するとします。 そのための別のAPI、 animateKeyframes
があります。 しかし、それを掘り下げる前に、アニメーションでフレームが何であるかを簡単に見てみましょう。
frame
とは何ですか?
開始状態から最終状態までのビューのフレーム変更/遷移のコレクションはanimation
として定義され、アニメーション中のビューの各位置はframe
と呼ばれます。
animateKeyframes
このAPIは、タイミングとトランジションが異なる複数のアニメーションを定義できるようにアニメーションを設計する方法を提供します。 これを投稿すると、APIはすべてのアニメーションを1つのシームレスなエクスペリエンスに統合するだけです。
画面上のボタンをランダムに動かしたいとします。 キーフレームアニメーションAPIを使用してこれを行う方法を見てみましょう。
UIView.animateKeyframes(withDuration: 5, //1 delay: 0, //2 options: .calculationModeLinear, //3 animations: { //4 UIView.addKeyframe( //5 withRelativeStartTime: 0.25, //6 relativeDuration: 0.25) { //7 self.button.center = CGPoint(x: self.view.bounds.midX, y: self.view.bounds.maxY) //8 } UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.25) { self.button.center = CGPoint(x: self.view.bounds.width, y: start.y) } UIView.addKeyframe(withRelativeStartTime: 0.75, relativeDuration: 0.25) { self.button.center = start } })
内訳は次のとおりです。
-
duration
アニメーションの継続時間を渡してAPIを呼び出します。 -
delay
アニメーションの初期遅延時間。 -
options
ビューアニメーションに適用するアニメーションカーブのタイプ。 -
animations
開発者/ユーザーによって設計されたすべてのキーフレームアニメーションを取得するブロック。 -
addKeyFrame
APIを呼び出して、すべてのアニメーションをデザインします。 この例では、ボタンの各動きを定義しました。 ブロックに追加して、必要な数のそのようなアニメーションを作成できます。 -
relativeStartTime
アニメーションブロックのコレクション内のアニメーションの開始時刻を定義します。 -
relativeDuration
この特定のアニメーションの全体的な継続時間を定義します。 -
center
この例では、ボタンのcenterプロパティを変更するだけで、ボタンを画面上で移動できます。
そして、これは最終的なアニメーションがどのように見えるかです:
CoreAnimation
UIKitベースのアニメーションは、内部でコアアニメーションに変換されます。 したがって、Core Animationフレームワークは、UIKitアニメーションのバッキングレイヤーまたはバックボーンとして機能します。 したがって、すべてのUIKitアニメーションAPIは、簡単に使用できる、または便利な方法でコアアニメーションAPIのカプセル化されたレイヤーにすぎません。
UIKitアニメーションAPIは、主にビューのアニメーション化可能なプロパティに使用されるため、ビューに対して実行されたアニメーションをあまり制御できません。 したがって、アニメーションのすべてのフレームを制御する必要があるこのような場合は、基盤となるコアアニメーションAPIを直接使用することをお勧めします。 または、UIViewアニメーションとコアアニメーションの両方を組み合わせて使用することもできます。
UIView +コアアニメーション
UIViewおよびCoreAnimation APIを使用してタイミング曲線を指定するとともに、同じボタン変更アニメーションを再作成する方法を見てみましょう。
CATransaction
のタイミング関数を使用して、アニメーション曲線を指定および制御できます。
CATransaction
のタイミング関数とUIViewアニメーションの組み合わせを利用して、コーナー半径を持つボタンサイズ変更アニメーションの例を見てみましょう。
let oldValue = button.frame.width/2 let newButtonWidth: CGFloat = 60 /* Do Animations */ CATransaction.begin() //1 CATransaction.setAnimationDuration(2.0) //2 CATransaction.setAnimationTimingFunction(CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)) //3 // View animations //4 UIView.animate(withDuration: 1.0) { self.button.frame = CGRect(x: 0, y: 0, width: newButtonWidth, height: newButtonWidth) self.button.center = self.view.center } // Layer animations let cornerAnimation = CABasicAnimation(keyPath: #keyPath(CALayer.cornerRadius)) //5 cornerAnimation.fromValue = oldValue //6 cornerAnimation.toValue = newButtonWidth/2 //7 button.layer.cornerRadius = newButtonWidth/2 //8 button.layer.add(cornerAnimation, forKey: #keyPath(CALayer.cornerRadius)) //9 CATransaction.commit() //10
内訳は次のとおりです。
-
begin
アニメーションコードブロックの開始を表します。 -
duration
全体的なアニメーションの長さ。 -
curve
アニメーションに適用する必要のあるタイミングカーブを表します。 -
UIView.animate
ボタンのフレームを変更する最初のアニメーション。 -
CABasicAnimation
ボタンのcornerRadius
をキーパスとして参照することにより、CABasicAnimation
オブジェクトを作成します。これは、アニメーション化するものだからです。 同様に、キーフレームアニメーションをきめ細かく制御したい場合は、CAKeyframeAnimation
クラスを使用できます。 -
fromValue
アニメーションの開始値、つまりアニメーションを開始する必要があるボタンの初期cornerRadius
値を表します。 -
toValue
アニメーションの最終値、つまりアニメーションを終了する必要があるボタンの最終的なcornerRadius
値を表します。 -
cornerRadius
ボタンのcornerRadius
プロパティをアニメーションの最終値で設定する必要があります。そうしないと、アニメーションの完了後にボタンのcornerRadius値が初期値に自動的に戻されます。 -
addAnimation
アニメーションを実行する必要のあるキーパスを表すことにより、アニメーションプロセス全体の構成を含むアニメーションオブジェクトをレイヤーにアタッチします。 -
commit
アニメーションコードブロックの終わりを表し、アニメーションを開始します。
最終的なアニメーションは次のようになります。
このブログは、Core AnimationフレームワークAPIのほとんどをきちんと説明し、すべてのステップをガイドする手順を備えているため、より高度なアニメーションを作成するのに役立つ優れた読み物です。
UIKitDynamics
UIKit Dynamicsは、UIKitの物理エンジンであり、衝突、重力、プッシュ、スナップなどの物理動作をUIKitコントロールに追加できます。
UIKitDynamicAnimator
これは、UIKit Dynamicsフレームワークの管理クラスであり、特定のUIコントロールによってトリガーされるすべてのアニメーションを規制します。
UIKitDynamicBehavior
これにより、アニメーターに物理動作を追加して、アニメーターにアタッチされたビューで実行できるようになります。
UIKitDynamicsのさまざまな種類の動作には次のものがあります。
-
UIAttachmentBehavior
-
UICollisionBehavior
-
UIFieldBehavior
-
UIGravityBehavior
-
UIPushBehavior
-
UISnapBehavior
UIKitDynamicsのアーキテクチャは次のようになります。 アイテム1から5は、単一のビューに置き換えることができることに注意してください。
ボタンにいくつかの物理的動作を適用してみましょう。 ボタンに重力を加えて、実際のオブジェクトを扱っているような感覚を与える方法を見ていきます。
var dynamicAnimator : UIDynamicAnimator! var gravityBehavior : UIGravityBehavior! dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1 gravityBehavior = UIGravityBehavior(items: [button]) //2 dynamicAnimator.addBehavior(gravityBehavior) //3
内訳は次のとおりです。
-
UIKitDynamicAnimator
アニメーションを実行するためのオーケストレーターとして機能するUIKitDynamicAnimator
オブジェクトを作成しました。 また、参照ビューとしてボタンのスーパービューを渡しました。 -
UIGravityBehavior
UIGravityBehavior
オブジェクトを作成し、この動作が注入される配列要素にボタンを渡します。 -
addBehavior
アニメーターに重力オブジェクトを追加しました。
これにより、次のようなアニメーションが作成されます。
画面の下部を地面と見なすようにアニメーターに指示する必要があります。 ここでUICollisionBehavior
が登場します。var dynamicAnimator : UIDynamicAnimator! var gravityBehavior : UIGravityBehavior! var collisionBehavior : UICollisionBehavior! dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1 gravityBehavior = UIGravityBehavior(items: [button]) //2 dynamicAnimator.addBehavior(gravityBehavior) //3 collisionBehavior = UICollisionBehavior(items: [button]) //4 collisionBehavior.translatesReferenceBoundsIntoBoundary = true //5 dynamicAnimator.addBehavior(collisionBehavior) //6
-
UICollisionBehavior
UICollisionBehavior
オブジェクトを作成し、ボタンを渡して、動作が要素に追加されるようにしました。 -
translatesReferenceBoundsIntoBoundary
このプロパティを有効にすると、アニメーターは参照ビューの境界を最後として取得するようになります。これは、この場合は画面の下部です。 -
addBehavior
ここでは、アニメーターに衝突動作を追加しました。
これで、ボタンが地面に当たって、以下に示すように静止するはずです。
それはかなりきちんとしていますね?
それでは、オブジェクトがよりリアルに感じられるように、バウンス効果を追加してみましょう。 そのために、UIDynamicItemBehavior
クラスを使用します。var dynamicAnimator : UIDynamicAnimator! var gravityBehavior : UIGravityBehavior! var collisionBehavior : UICollisionBehavior! var bouncingBehavior : UIDynamicItemBehavior! dynamicAnimator = UIDynamicAnimator(referenceView: self.view) //1 gravityBehavior = UIGravityBehavior(items: [button]) //2 dynamicAnimator.addBehavior(gravityBehavior) //3 collisionBehavior = UICollisionBehavior(items: [button]) //4 collisionBehavior.translatesReferenceBoundsIntoBoundary = true //5 dynamicAnimator.addBehavior(collisionBehavior) //6 //Adding the bounce effect bouncingBehavior = UIDynamicItemBehavior(items: [button]) //7 bouncingBehavior.elasticity = 0.75 //8 dynamicAnimator.addBehavior(bouncingBehavior) //9
-
UIDynamicItemBehavior
UIDynamicItemBehavior
オブジェクトを作成し、ボタンを渡して、動作が要素に追加されるようにしました。 -
elasticity
値は0-1の間でなければなりません。これは、弾力性、つまり、オブジェクトがヒットしたときにオブジェクトが地面に跳ね返る回数を表します。 ここで魔法が起こります。このプロパティを微調整することで、ボール、ボトル、ハードオブジェクトなどのさまざまな種類のオブジェクトを区別できます。 -
addBehavior
ここでは、アニメーターに衝突動作を追加しました。
これで、以下に示すように、ボタンが地面に当たるとバウンドするはずです。
このリポジトリは非常に役立ち、動作中のすべてのUIKitDynamicsの動作を示します。 また、各動作を試すためのソースコードも提供します。 私の意見では、それはビューでiOSアニメーションを実行する方法の広範なリストとして役立つはずです!
次のセクションでは、アニメーションのパフォーマンスを測定するのに役立つツールについて簡単に説明します。 また、開発時間を大幅に節約できるため、Xcodeビルドを最適化する方法を検討することをお勧めします。
性能調整
このセクションでは、iOSアニメーションのパフォーマンスを測定および調整する方法を見ていきます。 iOS開発者は、アプリ全体のパフォーマンスを測定するために、メモリリークや割り当てなどのXcodeインスツルメントをすでに使用している可能性があります。 同様に、アニメーションのパフォーマンスを測定するために使用できる機器があります。
Core Animation
Instrument
Core Animation
インストゥルメントを試してみると、アプリ画面が提供するFPSを確認できるはずです。 これは、iOSアプリでレンダリングされたアニメーションのパフォーマンス/速度を測定するための優れた方法です。
描く
影のような効果のある画像のような重いコンテンツを表示するアプリでは、FPSが大幅に低下します。 このような場合、画像をUIImageView
のimageプロパティに直接割り当てるのではなく、Core GraphicsAPIを使用してコンテキスト内で画像を個別に描画してみてください。 これにより、メインスレッドではなく別のスレッドで実行される場合に画像解凍ロジックが非同期で実行されるため、画像の表示時間が大幅に短縮されます。
ラスタライズ
ラスタライズは、複雑なレイヤー情報をキャッシュして、これらのビューがレンダリングされるたびに再描画されないようにするために使用されるプロセスです。 ビューの再描画はFPSの低下の主な原因であるため、何度も再利用される予定のビューにラスタライズを適用するのが最適です。
まとめ
結論として、iOSアニメーションに役立つリソースのリストもまとめました。 これは、iOSアニメーションで作業するときに非常に便利です。 さらに、この一連のデザインツールは、アニメーションを詳しく調べる前の(デザイン)ステップとして役立つ場合があります。
iOSアニメーションを取り巻くトピックをできるだけ多くカバーできたと思います。 この記事で見逃したことがある場合は、下のコメントセクションでお知らせください。追加させていただきます。