trying to animate a constraint in swift

后端 未结 6 1929
离开以前
离开以前 2020-11-29 16:00

I have a UITextField that I want to enlarge its width when tapped on. I set up the constraints and made sure the constraint on the left has the lower priority t

相关标签:
6条回答
  • 2020-11-29 16:23

    SWIFT 4.x :

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

    Example with completion:

    self.mConstraint.constant = 100
    UIView.animate(withDuration: 0.3, animations: {
            self.view.layoutIfNeeded()
        }, completion: {res in
            //Do something
    })
    
    0 讨论(0)
  • 2020-11-29 16:28

    Watch this.

    The video says that you need to just add self.view.layoutIfNeeded() like the following:

    UIView.animate(withDuration: 1.0, animations: {
           self.centerX.constant -= 75
           self.view.layoutIfNeeded()
    }, completion: nil)
    
    0 讨论(0)
  • 2020-11-29 16:29

    In my case, I only updated the custom view.

    // 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()
    }
    
    0 讨论(0)
  • 2020-11-29 16:36

    With Swift 5 and iOS 12.3, according to your needs, you may choose one of the 3 following ways in order to solve your problem.


    #1. Using UIView's animate(withDuration:animations:) class method

    animate(withDuration:animations:) has the following declaration:

    Animate changes to one or more views using the specified duration.

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

    The Playground code below shows a possible implementation of animate(withDuration:animations:) in order to animate an Auto Layout constraint's constant change.

    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. Using UIViewPropertyAnimator's init(duration:curve:animations:) initialiser and startAnimation() method

    init(duration:curve:animations:) has the following declaration:

    Initializes the animator with a built-in UIKit timing curve.

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

    The Playground code below shows a possible implementation of init(duration:curve:animations:) and startAnimation() in order to animate an Auto Layout constraint's constant change.

    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()
    

    #3. Using UIViewPropertyAnimator's runningPropertyAnimator(withDuration:delay:options:animations:completion:) class method

    runningPropertyAnimator(withDuration:delay:options:animations:completion:) has the following declaration:

    Creates and returns an animator object that begins running its animations immediately.

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

    The Playground code below shows a possible implementation of runningPropertyAnimator(withDuration:delay:options:animations:completion:) in order to animate an Auto Layout constraint's constant change.

    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()
    
    0 讨论(0)
  • 2020-11-29 16:42

    It's very important to point out that view.layoutIfNeeded() applies to the view subviews only.

    Therefore to animate the view constraint, it is important to call it on the view-to-animate superview as follows:

        topConstraint.constant = heightShift
    
        UIView.animate(withDuration: 0.3) {
    
            // request layout on the *superview*
            self.view.superview?.layoutIfNeeded()
        }
    

    An example for a simple layout as follows:

    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()
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-29 16:46

    You need to first change the constraint and then animate the update.
    This should be in the superview.

    self.nameInputConstraint.constant = 8
    

    Swift 2

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

    Swift 3, 4, 5

    UIView.animate(withDuration: 0.5) {
        self.view.layoutIfNeeded()
    }
    
    0 讨论(0)
提交回复
热议问题