简体   繁体   中英

How animate UIView height constraint in Swift programmatically without making an IBOutlet?

I have created a button which is attached to the top, leading and trailing and has fixed height. And when I'm tapping the button the new UIView instance should appear with animation.

import UIKit

class ViewController: UIViewController {

var topButton = UIButton()
var myView = UIView()

override func viewDidLoad() {
    super.viewDidLoad()

    topButton = UIButton(type: .roundedRect)
    topButton.setTitle("Add Acctivity", for: .normal)
    topButton.backgroundColor = UIColor.purple
    topButton.setTitleColor(UIColor.white, for: .normal)
    topButton.titleLabel?.font = UIFont(name: "System", size: 26)
    topButton.translatesAutoresizingMaskIntoConstraints = false
    topButton.addTarget(self, action: #selector(expandMenu), for: .touchUpInside)
    view.addSubview(topButton)

    topButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 0).isActive = true
    topButton.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true
    topButton.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive = true
    topButton.heightAnchor.constraint(equalToConstant: 70).isActive = true

    myView.backgroundColor = UIColor.blue
    myView.translatesAutoresizingMaskIntoConstraints = false
    view.addSubview(myView)
    myView.topAnchor.constraint(equalTo: view.topAnchor, constant: 70).isActive = true
    myView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 0).isActive = true
    myView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: 0).isActive = true
    myView.heightAnchor.constraint(equalToConstant: 100).isActive = true

}

@objc func expandMenu() {

   myView.heightAnchor.constraint(equalToConstant: 300).isActive = true

    UIView.animate(withDuration: 1) {

        self.view.layoutIfNeeded()
    }
}



}

即使我将高度设置为300也无济于事

And the interesting thing is when I'm putting the height smaller than its initial value the animation works.

在此处输入图片说明

I saw many tutorials when people are creating IBOutlet from storyboard and then changing its constant value. But I'm wondering how to do that programmatically.

The issue in your code is that you are trying to reactivate another constraint that describes the height of myView , by saying (in expandMenu() ):

myView.heightAnchor.constraint(equalToConstant: 300).isActive = true

I would assume that you are getting a runtime warning similar to:

[LayoutConstraints] Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. ( "NSLayoutConstraint:0x60400008e5b0 UIView:0x7fa16a419450.height == 100 (active)>", "NSLayoutConstraint:0x608000097e30 UIView:0x7fa16a419450.height == 300 (active)>" )

Will attempt to recover by breaking constraint

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in may also be helpful.

means that myView already has a constraint for height, which is (in viewDidLoad() ):

myView.heightAnchor.constraint(equalToConstant: 100).isActive = true

What you should do instead is to change the constant value of the same constraint instead. You could achieve it like this:

Declare a NSLayoutConstraint as instance variable:

var myViewHeightConstraint: NSLayoutConstraint!

and in viewDidLoad() :

myViewHeightConstraint = NSLayoutConstraint(item: myView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 0.0, constant: 100)
myViewHeightConstraint.isActive = true

instead of:

myView.heightAnchor.constraint(equalToConstant: 100).isActive = true

Finally, in expandMenu() :

myViewHeightConstraint.constant = 300

instead of:

myView.heightAnchor.constraint(equalToConstant: 300).isActive = true

Output:

在此处输入图片说明


Furthermore:

If you are aiming to let the same button to achieve the expand/collapse behavior, you would need to simply implement it as (in expandMenu() ):

myViewHeightConstraint.constant = myViewHeightConstraint.constant == 300 ? 100 : 300

The constraint method returns an NSLayoutConstraint . You can assign it to a class level variable:

var heightConstraint: NSLayoutConstraint!

override func viewDidLoad() {
    // ...

    heightConstraint = myView.heightAnchor.constraint(equalToConstant: 100)
    heightConstraint.isActive = true
}

And then you will have a property heightConstraint that is very much like an IBOutlet . You can animate this the same way you animate an IBOutlet constraint.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM