UIKitとUIViewを使用してビューでiOSアニメーションを実行する

公開: 2022-03-10
簡単な要約↬この記事は、iOSアニメーションの入門書として、さまざまな方法を網羅的にカバーすることを目的としています。 まず、アニメーションの基本を理解し、コアフレームワークに移り、提供されているさまざまな方法を使用して単一の例を作成し、最後にパフォーマンスを調整する方法を検討します。

私は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 }

ここで行っていることは次のとおりです。

  1. ブロック内に記述されているアニメーションの実行時間を表すduration値を渡してUIView.animateメソッドを呼び出します。
  2. アニメーションの最終状態を表すボタンの新しいフレームを設定します。
  3. ボタンの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)

使用するパラメータのセットは次のとおりです。

  1. duration
    コードのブロックを実行する時間を決定するアニメーションの期間を表します。
  2. delay
    アニメーションの開始前に必要な初期遅延を表します。
  3. SpringWithDamping
    ビューに動作させたい弾力性のある効果の値を表します。 値は0から1の間でなければなりません。値が小さいほど、ばねの振動が大きくなります。
  4. velocity
    アニメーションを開始する速度を表します。
  5. options
    ビューアニメーションに適用するアニメーションカーブのタイプ。
  6. 最後に、アニメーション化する必要のあるボタンのフレームを設定するコードのブロック。 前のアニメーションと同じです。

そして、上記のアニメーション構成でのアニメーションは次のようになります。

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

これが私たちがしていることです:

  1. 継続時間とアニメーション曲線を渡すことにより、 UIViewPropertyを呼び出します。
  2. 上記の両方の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 } })

内訳は次のとおりです。

  1. duration
    アニメーションの継続時間を渡してAPIを呼び出します。
  2. delay
    アニメーションの初期遅延時間。
  3. options
    ビューアニメーションに適用するアニメーションカーブのタイプ。
  4. animations
    開発者/ユーザーによって設計されたすべてのキーフレームアニメーションを取得するブロック。
  5. addKeyFrame
    APIを呼び出して、すべてのアニメーションをデザインします。 この例では、ボタンの各動きを定義しました。 ブロックに追加して、必要な数のそのようなアニメーションを作成できます。
  6. relativeStartTime
    アニメーションブロックのコレクション内のアニメーションの開始時刻を定義します。
  7. relativeDuration
    この特定のアニメーションの全体的な継続時間を定義します。
  8. 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

内訳は次のとおりです。

  1. begin
    アニメーションコードブロックの開始を表します。
  2. duration
    全体的なアニメーションの長さ。
  3. curve
    アニメーションに適用する必要のあるタイミングカーブを表します。
  4. UIView.animate
    ボタンのフレームを変更する最初のアニメーション。
  5. CABasicAnimation
    ボタンのcornerRadiusをキーパスとして参照することにより、 CABasicAnimationオブジェクトを作成します。これは、アニメーション化するものだからです。 同様に、キーフレームアニメーションをきめ細かく制御したい場合は、 CAKeyframeAnimationクラスを使用できます。
  6. fromValue
    アニメーションの開始値、つまりアニメーションを開始する必要があるボタンの初期cornerRadius値を表します。
  7. toValue
    アニメーションの最終値、つまりアニメーションを終了する必要があるボタンの最終的なcornerRadius値を表します。
  8. cornerRadius
    ボタンのcornerRadiusプロパティをアニメーションの最終値で設定する必要があります。そうしないと、アニメーションの完了後にボタンのcornerRadius値が初期値に自動的に戻されます。
  9. addAnimation
    アニメーションを実行する必要のあるキーパスを表すことにより、アニメーションプロセス全体の構成を含むアニメーションオブジェクトをレイヤーにアタッチします。
  10. 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

内訳は次のとおりです。

  1. UIKitDynamicAnimator
    アニメーションを実行するためのオーケストレーターとして機能するUIKitDynamicAnimatorオブジェクトを作成しました。 また、参照ビューとしてボタンのスーパービューを渡しました。
  2. UIGravityBehavior
    UIGravityBehaviorオブジェクトを作成し、この動作が注入される配列要素にボタンを渡します。
  3. 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
  4. UICollisionBehavior
    UICollisionBehaviorオブジェクトを作成し、ボタンを渡して、動作が要素に追加されるようにしました。
  5. translatesReferenceBoundsIntoBoundary
    このプロパティを有効にすると、アニメーターは参照ビューの境界を最後として取得するようになります。これは、この場合は画面の下部です。
  6. 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
  7. UIDynamicItemBehavior
    UIDynamicItemBehaviorオブジェクトを作成し、ボタンを渡して、動作が要素に追加されるようにしました。
  8. elasticity
    値は0-1の間でなければなりません。これは、弾力性、つまり、オブジェクトがヒットしたときにオブジェクトが地面に跳ね返る回数を表します。 ここで魔法が起こります。このプロパティを微調整することで、ボール、ボトル、ハードオブジェクトなどのさまざまな種類のオブジェクトを区別できます。
  9. addBehavior
    ここでは、アニメーターに衝突動作を追加しました。

これで、以下に示すように、ボタンが地面に当たるとバウンドするはずです。

このリポジトリは非常に役立ち、動作中のすべてのUIKitDynamicsの動作を示します。 また、各動作を試すためのソースコードも提供します。 私の意見では、それはビューでiOSアニメーションを実行する方法の広範なリストとして役立つはずです!

次のセクションでは、アニメーションのパフォーマンスを測定するのに役立つツールについて簡単に説明します。 また、開発時間を大幅に節約できるため、Xcodeビルドを最適化する方法を検討することをお勧めします。

性能調整

このセクションでは、iOSアニメーションのパフォーマンスを測定および調整する方法を見ていきます。 iOS開発者は、アプリ全体のパフォーマンスを測定するために、メモリリークや割り当てなどのXcodeインスツルメントをすでに使用している可能性があります。 同様に、アニメーションのパフォーマンスを測定するために使用できる機器があります。

Core Animation Instrument

Core Animationインストゥルメントを試してみると、アプリ画面が提供するFPSを確認できるはずです。 これは、iOSアプリでレンダリングされたアニメーションのパフォーマンス/速度を測定するための優れた方法です。

描く

影のような効果のある画像のような重いコンテンツを表示するアプリでは、FPSが大幅に低下します。 このような場合、画像をUIImageViewのimageプロパティに直接割り当てるのではなく、Core GraphicsAPIを使用してコンテキスト内で画像を個別に描画してみてください。 これにより、メインスレッドではなく別のスレッドで実行される場合に画像解凍ロジックが非同期で実行されるため、画像の表示時間が大幅に短縮されます。

ラスタライズ

ラスタライズは、複雑なレイヤー情報をキャッシュして、これらのビューがレンダリングされるたびに再描画されないようにするために使用されるプロセスです。 ビューの再描画はFPSの低下の主な原因であるため、何度も再利用される予定のビューにラスタライズを適用するのが最適です。

まとめ

結論として、iOSアニメーションに役立つリソースのリストもまとめました。 これは、iOSアニメーションで作業するときに非常に便利です。 さらに、この一連のデザインツールは、アニメーションを詳しく調べる前の(デザイン)ステップとして役立つ場合があります。

iOSアニメーションを取り巻くトピックをできるだけ多くカバーできたと思います。 この記事で見逃したことがある場合は、下のコメントセクションでお知らせください。追加させていただきます。