Animation: frame vs layout constraints


最初のトピックとしてアニメーションを選択しました.アプリケーションを作成するときに適切なアニメーションを適用するのは容易ではありませんこの授業では、アニメーションの基礎知識を紹介します.

Animation


必要な理由

  • のアニメーションがなければ、アプリケーションは硬く感じるかもしれません.アニメーションを使用すると、アプリケーションの可用性が向上します.
  • のアニメーションがあれば、ユーザーはもっと投入されます!
  • 定義#テイギ#


    これは、ビューの状態が時間とともに変化することを意味します.

    アニメーションの3要素

  • 時間:ビューの変化はどのくらい続きますか?
  • 終了:アニメーション終了時の最終ビューの状態
  • 値:ビューはどのくらい変化しますか?(ex.移動距離、拡大倍率)
  • animation API

    UIView.animate(withDuration: 1.0, // 애니메이션의 지속시간
                   delay: 1.0, // 애니메이션이 시작하기 전에 기다릴 시간
                   options: .curveEaseInOut, // 애니메이션 옵션
                   animations: {}, // 애니메이션 내용
                   completion: { _ in return } // 애니메이션이 끝나면 실행할 클로저
    )

    実習の準備をする


    アニメーションのターゲットとして青い円を用意し、アニメーションを開始するボタンを用意します.
    import UIKit
    
    class VC1: UIViewController {
        
        // MARK: Properties
        
    		// 파란색 원
        let circle: UIView = {
            let view = UIView()
            view.frame.size = CGSize(width: 100, height: 100)
            view.layer.cornerRadius = 100 / 2
            view.backgroundColor = .blue
            return view
        }()
        
    		// 애니메이션 버튼
        let animationButton: UIButton = {
            let button = UIButton()
            button.setTitle("animate!", for: .normal)
            button.setTitleColor(.black, for: .normal)
            button.addTarget(self, action: #selector(animateCircle), for: .touchUpInside)
            return button
        }()
    
        // MARK: LifeCycle
        
        override func viewDidLoad() {
            super.viewDidLoad()
            view.backgroundColor = .white
            configureUI()
        }
        
        // MARK: Selector
        
        @objc func animateCircle() {
            UIView.animate(withDuration: 1.0, animations: {
                // 애니메이션 정의
            })
        }
        
        // MARK: Helpers
        
        func configureUI() {
            view.addSubview(circle)
            circle.frame.origin = CGPoint(x: view.frame.width / 2 - 50, y: 100)
            
            view.addSubview(animationButton)
            animationButton.translatesAutoresizingMaskIntoConstraints = false
            animationButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
            animationButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -100).isActive = true
        }
    }

    フレームを使用したアニメーションの作成


    フレームワークは、オブジェクトの絶対位置と絶対サイズを定義します.フレームは原点と寸法で構成されています.原点は原点(左上隅)の位置、寸法は大きさを表します.
    フレーム値の原点値を変更することで、オブジェクトを移動できます.
    @objc func animateCircle() {
            UIView.animate(withDuration: 1.0, animations: {
                self.circle.frame.origin.y = 200
            })
        }

    レイアウトコンストレイントを使用したアニメーションの作成


    実戦では、フレーム内のオブジェクトをどこかに置くことはめったにありません.ほとんどの場合、レイアウトコンストレイントを定義して位置を定義します.これらのコンストレイントは、他のオブジェクトとの相対的な位置を指定します.そこで、レイアウトコンストレイントを使用してアニメーションを定義する方法についても説明します.
    ""レイアウトコンストレイント"を使用してアニメーションを作成するには、アニメーション前のレイアウトコンストレイントをメンバー変数として宣言する必要があります.これは、対応するレイアウトコンストレイントを無効にし、新しいレイアウトコンストレイントを適用する必要があるためです.
    let circle: UIView = {
        let view = UIView()
        view.widthAnchor.constraint(equalToConstant: 100).isActive = true
        view.heightAnchor.constraint(equalToConstant: 100).isActive = true
        view.layer.cornerRadius = 100 / 2
        view.backgroundColor = .blue
        return view
    }()
    
    lazy var beforeAnimation = self.circle.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 100)
    // 처음에 화면에 띄우는 헬퍼 함수
    func configureUI() {
        view.addSubview(circle)
        circle.translatesAutoresizingMaskIntoConstraints = false
        circle.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        beforeAnimation.isActive = true
        
        view.addSubview(animationButton)
        animationButton.translatesAutoresizingMaskIntoConstraints = false
        animationButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
        animationButton.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -100).isActive = true
    }
    レイアウトコンストレイントの使用方法はフレームワークとは異なります.アニメーションモジュールを実装する前に、レイアウトコンストレイントを適用してください.キャンセルするレイアウト制約をメンバー変数として削除する理由は、次のコレクタ関数にアクセスするためです.既存のレイアウトコンストレイントと新しいレイアウトコンストレイントが競合するため、キャンセルしないとアニメーションは実行されません.
    新しいレイアウトコンストレイントが適用されたからといって、すぐにビューを変更することはありません.アニメーションモジュールでlayoutifNeeded()メソッドを使用して更新する必要があります.
    @objc func animateCircle() {
        beforeAnimation.isActive = false
        circle.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 200).isActive = true
        UIView.animate(withDuration: 1.0, animations: {
            self.view.layoutIfNeeded()
        })
    }
    🚫  メンバー変数として単独で減算するほか、以下のように同じレイアウトコンストレイント、=falseを書き直すことでキャンセルできるという意見もたまにあります.これではだめです.同じレイアウトコンストレイントを再適用しても、異なるメモリ領域に格納されます.したがって、既存のtrueに設定されたレイアウトコンストレイントはfalseではありません.
    @objc func animateCircle() {
        circle.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 100) = false
        circle.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 200) = true
        UIView.animate(withDuration: 1.0, animations: {
            self.view.layoutIfNeeded()
        })
    }

    いくつかの適用アニメーション


    基本アニメーションに加えて、いくつかの特殊なアニメーションAPIも提供されています.ここで簡単に紹介します各パラメータの意味については、本書を参照してください.

    スプリングアニメーション

    @objc func animateCircle() {
        beforeAnimation.isActive = false
        circle.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 200).isActive = true
        UIView.animate(withDuration: 1.0,
            delay: 0.2,
            usingSpringWithDamping: 0.2,
            initialSpringVelocity: 2,
            animations: {
                self.view.layoutIfNeeded()
            })
    }

    反転アニメーションを追加


    アニメーションではなくAPIでアニメーションを使用できます.
    @objc func animateCircle() {
            beforeAnimation.isActive = false
            circle.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 200).isActive = true
            UIView.transition(with: circle,
                duration: 1,
                options: .transitionFlipFromLeft,
                animations: { self.view.layoutIfNeeded() },
                completion: nil)
        }

    連続アニメーション


    アニメーションが終了したら、タイマーを使用して次のアニメーションを続行します.

    完了パラメータの使用


    animateメソッドのcompletionは、アニメーションが終了した後に実行するモジュールを定義するパラメータです.ここに別のアニメーションを挿入すると、アニメーションを連続的に実行できます.
    @objc func animateCircle() {
        beforeAnimation.isActive = false
        circle.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 200).isActive = true
        UIView.animate(withDuration: 1.0, animations: { self.view.layoutIfNeeded() },
            completion: { _ in
            self.beforeAnimation2.isActive = false
            self.circle.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 100).isActive = true
            UIView.animate(withDuration: 1.0, animations: { self.view.layoutIfNeeded() })
        })
    }

    タイマーの使用(DispatchQueue.main.asyncAfter)


    タイマーの使い方.別のアニメーションを最初のアニメーションの持続時間の後に続けます.
    @objc func animateCircle() {
        beforeAnimation.isActive = false
        circle.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 200).isActive = true
        UIView.animate(withDuration: 1.0, animations: { self.view.layoutIfNeeded() })
        DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
            self.beforeAnimation2.isActive = false
            self.circle.centerXAnchor.constraint(equalTo: self.view.centerXAnchor, constant: 100).isActive = true
            UIView.animate(withDuration: 1.0, animations: { self.view.layoutIfNeeded() })
       }
    }

    終了時..。


    story boardを使用してoutletをインポートしたlayoutコンストレイントは多くのアニメーションを作成しましたが、コード定義のlayoutコンストレイントを使用して初めて作成され、途中で多くのエラーが発生しました.やはりコードは自分で作成して実行して進歩した
    もっと素晴らしいアニメを作る日まで頑張ります