[xcode] 신속한 구속 조건 애니메이션

탭 할 때 너비를 늘리고 싶은 UITextField가 있습니다. 제약 조건을 설정하고 왼쪽의 제약 조건이 오른쪽에서 애니메이션을 적용하려는 것보다 우선 순위가 낮은 지 확인했습니다.

사용하려고하는 코드는 다음과 같습니다.

  // move the input box
    UIView.animateWithDuration(10.5, animations: {
        self.nameInputConstraint.constant = 8
        }, completion: {
            (value: Bool) in
            println(">>> move const")
    })

이것은 작동하지만 즉시 발생하는 것으로 보이며 아무런 움직임도없는 것 같습니다. 나는 아무것도 빠뜨리지 않도록 10 초를 설정하려고했지만 같은 결과를 얻었습니다.

nameInputConstraint는 IB에서 클래스에 연결하기 위해 드래그하여 제어하는 ​​제약 조건의 이름입니다.

미리 도와 주셔서 감사합니다!



답변

먼저 제약 조건을 변경 한 다음 업데이트에 애니메이션을 적용해야합니다.

self.nameInputConstraint.constant = 8

스위프트 2

UIView.animateWithDuration(0.5) {
    self.view.layoutIfNeeded()
}

스위프트 3, 4, 5

UIView.animate(withDuration: 0.5) {
    self.view.layoutIfNeeded()
}


답변

스위프트 4.x :

self.mConstraint.constant = 100.0
UIView.animate(withDuration: 0.3) {
        self.view.layoutIfNeeded()
}

완료된 예 :

self.mConstraint.constant = 100
UIView.animate(withDuration: 0.3, animations: {
        self.view.layoutIfNeeded()
    }, completion: {res in
        //Do something
})


답변

view.layoutIfNeeded()뷰 서브 뷰에만 적용되는 것을 지적하는 것이 매우 중요 합니다.

따라서 뷰 제약 조건에 애니메이션을 적용하려면 다음과 같이 대 애니메이션 슈퍼 뷰 에서 호출해야 합니다.

    topConstraint.constant = heightShift

    UIView.animate(withDuration: 0.3) {

        // request layout on the *superview*
        self.view.superview?.layoutIfNeeded()
    }

간단한 레이아웃의 예는 다음과 같습니다.

class MyClass {

    /// Container view
    let container = UIView()
        /// View attached to container
        let view = UIView()

    /// Top constraint to animate
    var topConstraint = NSLayoutConstraint()


    /// Create the UI hierarchy and constraints
    func createUI() {
        container.addSubview(view)

        // Create the top constraint
        topConstraint = view.topAnchor.constraint(equalTo: container.topAnchor, constant: 0)


        view.translatesAutoresizingMaskIntoConstraints = false

        // Activate constaint(s)
        NSLayoutConstraint.activate([
           topConstraint,
        ])
    }

    /// Update view constraint with animation
    func updateConstraint(heightShift: CGFloat) {
        topConstraint.constant = heightShift

        UIView.animate(withDuration: 0.3) {

            // request layout on the *superview*
            self.view.superview?.layoutIfNeeded()
        }
    }
}


답변

Swift 5 및 iOS 12.3에서는 필요에 따라 문제를 해결하기 위해 다음 3 가지 방법 중 하나를 선택할 수 있습니다.


#1. 사용 UIViewanimate(withDuration:animations:)클래스 메소드

animate(withDuration:animations:) 다음과 같은 선언이 있습니다.

지정된 지속 시간을 사용하여 하나 이상의 뷰로 애니메이션을 변경합니다.

class func animate(withDuration duration: TimeInterval, animations: @escaping () -> Void)

아래의 Playground 코드 animate(withDuration:animations:)는 자동 레이아웃 제약 조건의 지속적인 변화를 애니메이션하기 위해 가능한 구현을 보여줍니다 .

import UIKit
import PlaygroundSupport

class ViewController: UIViewController {

    let textView = UITextView()
    lazy var heightConstraint = textView.heightAnchor.constraint(equalToConstant: 50)

    override func viewDidLoad() {
        view.backgroundColor = .white
        view.addSubview(textView)

        textView.backgroundColor = .orange
        textView.isEditable = false
        textView.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."

        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.topAnchor.constraint(equalToSystemSpacingBelow: view.layoutMarginsGuide.topAnchor, multiplier: 1).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
        textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true
        heightConstraint.isActive = true

        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(doIt(_:)))
        textView.addGestureRecognizer(tapGesture)
    }

    @objc func doIt(_ sender: UITapGestureRecognizer) {
        heightConstraint.constant = heightConstraint.constant == 50 ? 150 : 50
        UIView.animate(withDuration: 2) {
            self.view.layoutIfNeeded()
        }
    }

}

PlaygroundPage.current.liveView = ViewController()

# 2. 사용 UIViewPropertyAnimatorinit(duration:curve:animations:)initialiser 및 startAnimation()방법을

init(duration:curve:animations:) 다음과 같은 선언이 있습니다.

내장 UIKit 타이밍 곡선을 사용하여 애니메이터를 초기화합니다.

convenience init(duration: TimeInterval, curve: UIViewAnimationCurve, animations: (() -> Void)? = nil)

아래의 Playground 코드 는 자동 레이아웃 제약 조건의 지속적인 변화를 애니메이션 init(duration:curve:animations:)하고 구현 startAnimation()하기 위해 가능한 구현을 보여줍니다 .

import UIKit
import PlaygroundSupport

class ViewController: UIViewController {

    let textView = UITextView()
    lazy var heightConstraint = textView.heightAnchor.constraint(equalToConstant: 50)

    override func viewDidLoad() {
        view.backgroundColor = .white
        view.addSubview(textView)

        textView.backgroundColor = .orange
        textView.isEditable = false
        textView.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."

        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.topAnchor.constraint(equalToSystemSpacingBelow: view.layoutMarginsGuide.topAnchor, multiplier: 1).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
        textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true
        heightConstraint.isActive = true

        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(doIt(_:)))
        textView.addGestureRecognizer(tapGesture)
    }

    @objc func doIt(_ sender: UITapGestureRecognizer) {
        heightConstraint.constant = heightConstraint.constant == 50 ? 150 : 50
        let animator = UIViewPropertyAnimator(duration: 2, curve: .linear, animations: {
            self.view.layoutIfNeeded()
        })
        animator.startAnimation()
    }

}

PlaygroundPage.current.liveView = ViewController()

#삼. 사용 UIViewPropertyAnimatorrunningPropertyAnimator(withDuration:delay:options:animations:completion:)클래스 메소드

runningPropertyAnimator(withDuration:delay:options:animations:completion:) 다음과 같은 선언이 있습니다.

애니메이션을 즉시 실행하기 시작하는 애니메이터 객체를 만들고 반환합니다.

class func runningPropertyAnimator(withDuration duration: TimeInterval, delay: TimeInterval, options: UIViewAnimationOptions = [], animations: @escaping () -> Void, completion: ((UIViewAnimatingPosition) -> Void)? = nil) -> Self

아래의 Playground 코드 runningPropertyAnimator(withDuration:delay:options:animations:completion:)는 자동 레이아웃 제약 조건의 지속적인 변화를 애니메이션하기 위해 가능한 구현을 보여줍니다 .

import UIKit
import PlaygroundSupport

class ViewController: UIViewController {

    let textView = UITextView()
    lazy var heightConstraint = textView.heightAnchor.constraint(equalToConstant: 50)

    override func viewDidLoad() {
        view.backgroundColor = .white
        view.addSubview(textView)

        textView.backgroundColor = .orange
        textView.isEditable = false
        textView.text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."

        textView.translatesAutoresizingMaskIntoConstraints = false
        textView.topAnchor.constraint(equalToSystemSpacingBelow: view.layoutMarginsGuide.topAnchor, multiplier: 1).isActive = true
        textView.leadingAnchor.constraint(equalTo: view.layoutMarginsGuide.leadingAnchor).isActive = true
        textView.trailingAnchor.constraint(equalTo: view.layoutMarginsGuide.trailingAnchor).isActive = true
        heightConstraint.isActive = true

        let tapGesture = UITapGestureRecognizer(target: self, action: #selector(doIt(_:)))
        textView.addGestureRecognizer(tapGesture)
    }

    @objc func doIt(_ sender: UITapGestureRecognizer) {
        heightConstraint.constant = heightConstraint.constant == 50 ? 150 : 50
        UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 2, delay: 0, options: [], animations: {
            self.view.layoutIfNeeded()
        })
    }

}

PlaygroundPage.current.liveView = ViewController()


답변

필자의 경우 사용자 정의보기 만 업데이트했습니다.

// DO NOT LIKE THIS
customView.layoutIfNeeded()    // Change to view.layoutIfNeeded()
UIView.animate(withDuration: 0.5) {
   customViewConstraint.constant = 100.0
   customView.layoutIfNeeded() // Change to view.layoutIfNeeded()
}


답변

시청 .

비디오는 self.view.layoutIfNeeded()다음과 같이 추가해야한다고 말합니다 .

UIView.animate(withDuration: 1.0, animations: {
       self.centerX.constant -= 75
       self.view.layoutIfNeeded()
}, completion: nil)


답변