0
votes

I'm working on adding error messages to my login screen.

While the code runs fine, and does what I want it to do. It causes a constraint error on execution.

Here are the effected constraints:

self.view.addConstraints(
    NSLayoutConstraint.constraintsWithVisualFormat(
        "V:|[topBar]-32-[emailInputField]-32-[passwordInputField]-32-[signInButton]-16-[resetPasswordButton]-[signUpButton]", options: nil, metrics: nil, views: viewsDictionary))
self.view.addConstraints(
    NSLayoutConstraint.constraintsWithVisualFormat(
        "V:|[topBar]-32-[emailIconBox]-32-[passwordIconBox]", options: nil, metrics: nil, views: viewsDictionary))

And here is the function that causes the errorView to appear.

// sign in button function
func signIn(sender: UIButton) {
self.view.endEditing(true)

if emailInputField.text.isEmpty {
    println("NO EMAIL")

    errorLabel.attributedText = UILabel.ErrorMessage("Form fields cannot be empty!")


    var viewsDictionary = [ "topBar":topBar,
        "errorView":errorView,
        "errorLabel":errorLabel,
        "emailInputField":emailInputField,
        "emailIconBox":emailIconBox,
        "passwordInputField":passwordInputField,
        "passwordIconBox":passwordIconBox,
        "signInButton":signInButton,
        "resetPasswordButton":resetPasswordButton,
        "signUpButton":signUpButton]

    self.view.addConstraints(
        NSLayoutConstraint.constraintsWithVisualFormat(
            "V:|[topBar]-16-[errorView]-16-[emailInputField]-32-[passwordInputField]-32-[signInButton]-16-[resetPasswordButton]-[signUpButton]", options: nil, metrics: nil, views: viewsDictionary))
    self.view.addConstraints(
        NSLayoutConstraint.constraintsWithVisualFormat(
            "V:|[topBar]-16-[errorView]-16-[emailIconBox]-32-[passwordIconBox]", options: nil, metrics: nil, views: viewsDictionary))
    self.view.addConstraints(
        NSLayoutConstraint.constraintsWithVisualFormat(
            "V:[errorView(50)]", options: NSLayoutFormatOptions(0), metrics: nil, views: viewsDictionary))
}
}

How do I change the constraints without breaking them?

I tried self.view.updateConstraints() - but that did nothing. I also tried removing the constraints just before adding them, but there was still an error.

Any help would be greatly appreciated!

EDIT:

I found an objective-c solution, to the constraint a variable with a constant and then changing the constant. - I tried translating this to swift. There's no errors when I run it, but my errorView does not show up (height doesn't change)

here's what I tried:

  1. I declared the variable in the ViewController class (before viewDidLoad)

    var errorViewHeight = NSLayoutConstraint()

  2. in the beginning of my function, I specify it.

    errorViewHeight = NSLayoutConstraint(item:errorView, attribute:NSLayoutAttribute.Height, relatedBy:NSLayoutRelation.Equal, toItem:nil, attribute:NSLayoutAttribute.NotAnAttribute, multiplier:1.0, constant:0)

  3. and lastly, after an if statement returns true, I attempt to animate it.

    UIView.animateWithDuration(0.2, animations: { () -> Void in self.errorViewHeight.constant = 50 self.view.layoutIfNeeded() })

EDIT:

Here's the error message:

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. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x170089e20 V:[UIView:0x174191780(0)]>",
    "<NSLayoutConstraint:0x170089fb0 V:[UIView:0x174191780(50)]>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x170089fb0 V:[UIView:0x174191780(50)]>

Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger.
The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
3
You can change the constraints without breaking them by only making sure that you are not breaking them. Jokes apart, can you show us the error you are getting.gagarwal
Where does error view come from? Are you adding it code, or in IB? The error is saying that you're setting the height to both 0 and 50.rdelmar
Looks like you are setting multiple Vertical constraints to "errorView". In the top two "addConstraints", there is no constraint set on "errorView" height. And in the last on you are setting height to 50. I believe these are causing the conflicts. You can remove the last "addConstraints" and instead set the height in the above two.gagarwal
I know what's causing the conflict, I Just can't figure out how to change a constraint without adding it like I did. I've struggled with it for about 10 hours now. I found an obj-c solution I tried to translate. I'll edit my post with it. (it was basically the same as you're saying, but I can't get it to work)MLyck

3 Answers

0
votes

I figured out how to change a constraint using a constant.

In the viewController class I defined the constraint:

var errorViewHeight:NSLayoutConstraint!

and in the viewDidLoad, I specified and added it to my UIView

errorViewHeight = NSLayoutConstraint(item:errorView, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute, multiplier:1.0, constant:0)
errorView.addConstraint(errorViewHeight)

From then on, I was able to change the height properly using the following line of code

errorViewHeight.constant = 50

hope that helped someone looking for the same problem.

0
votes

You can change any constraint by adding the following extension , it is excellent if you are deploying to multiple devices :

extension UIView
{
    func updateHieghtForView()
    {
        var constant = CGFloat()
        // change the constant by switching device type by screen size 
        let allConstraints = self.constraints
        for heightConstraint in allConstraints
        {
            if heightConstraint.firstAttribute == .Height 
            {
                self.removeConstraint(heightConstraint)
            }
        }
        let layOutConstaint = NSLayoutConstraint(item: self,
                                                 attribute: .Height,
                                                 relatedBy: .Equal,
                                                 toItem: nil,
                                                 attribute:.Height,
                                                 multiplier: 1,
                                                 constant: constant)
        self.addConstraint(layOutConstaint)
        self.updateConstraints()
    }
}
0
votes

I answer I want to add is, some people have this habit of setting Constraints inside viewDidLayout method, so when you change or edit any constraint, it will give you this error coz viewDidLayout doesn't work like viewDidLoad or other functions. So my advice is, if you are doing something like this, please use viewDidAppear instead of viewDidLayout, best would be to use viewDidLoad.