How can I set priority on constraints in Swift?

Viewed 12005

I've been struggling to make priority on constraints work programmatically in Swift.

My goal is to have the meetingFormView no more than 300 wide. Using IB I would give the width constraint a lower priority and give a higher priority to the "lessThanOrEqualToConstant". But I can't get it to work.

I've tried this:

meetingFormView.translatesAutoresizingMaskIntoConstraints = false

let constraintWidth = NSLayoutConstraint(
        item: meetingFormView,
        attribute: NSLayoutAttribute.width,
        relatedBy: NSLayoutRelation.equal,
        toItem: startView,
        attribute: NSLayoutAttribute.width,
        multiplier: 1,
        constant: 0)
constraintWidth.priority = .defaultHigh

NSLayoutConstraint.activate([
    meetingFormView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 20),
    meetingFormView.heightAnchor.constraint(equalToConstant: 170),
    meetingFormView.widthAnchor.constraint(lessThanOrEqualToConstant: 300),
    meetingFormView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
    constraintWidth
])
2 Answers

It actually seems to take three lines of code to set up a prioritized "anchor-based" constraint in code:

let widthConstraint = meetingFormView.widthAnchor.constraint(equalToConstant: 170)
widthConstraint.priority = UILayoutPriority(rawValue: 500)
widthConstraint.isActive = true

It seems like if I try to set isActive with the let declare Xcode (maybe Swift?) doesn't recognize that the type is NSLayoutConstraint. And using UILayoutPriority(rawValue:) seems to be the best (only?) way to set priorities.

While this answer doesn't conform exactly with what you are doing, I believe it will work with IB. Just replace the let with creating an IBOutlet and there should be no need for the isActive line.

Obviously, to change the priority later in code you just need:

widthConstraint.priority = UILayoutPriority(rawValue: 750)

You can write a small extension like this:

extension NSLayoutConstraint
{
    func withPriority(_ priority: Float) -> NSLayoutConstraint
    {
        self.priority = UILayoutPriority(priority)
        return self
    }
}

then use it like this:

NSLayoutConstraint.activate([
    ...
    meetingFormView.widthAnchor.constraint(lessThanOrEqualToConstant: 300).withPriority(500),
    ...
])
Related