jl303
jl303

Reputation: 1609

iOS Constraints Not Updating After Setting Programatically

I'm trying to position all the ui objects when loading, but it doesn't seem to change. From top to bottom, the layout is : host, port, user, and password, and I aligned:
* middle of all with middle of view
* top of host with top of layout margin
* top of port with bottom of host
* top of user with bottom of port
* top of password with bottom of user
Could someone please help? Here's the code. Thank you!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    self.view.translatesAutoresizingMaskIntoConstraints = false
    host.centerXAnchor.constraint(equalTo:self.view.centerXAnchor).isActive = true
    host.topAnchor.constraint(equalTo:self.view.layoutMarginsGuide.topAnchor, constant:20.0).isActive = true
    port.centerXAnchor.constraint(equalTo:self.view.centerXAnchor).isActive = true
    port.topAnchor.constraint(equalTo:host.bottomAnchor, constant:20.0).isActive = true
    user.centerXAnchor.constraint(equalTo:self.view.centerXAnchor).isActive = true
    user.topAnchor.constraint(equalTo:port.bottomAnchor, constant:20.0).isActive = true
    password.centerXAnchor.constraint(equalTo:self.view.centerXAnchor).isActive = true
    password.topAnchor.constraint(equalTo:user.bottomAnchor, constant:20.0).isActive = true
    connectButton.centerXAnchor.constraint(equalTo:self.view.centerXAnchor).isActive = true
    connectButton.topAnchor.constraint(equalTo:password.bottomAnchor, constant:20.0).isActive = true
    self.view.setNeedsUpdateConstraints()
    self.view.setNeedsLayout()
    self.view.updateConstraints()
}

Then I get many of these errors in the console:

[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.
(Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints)
(
"<NSAutoresizingMaskLayoutConstraint:0x174288930 h=--& v=--& UITextField:0x10141f240.midY == 256   (active)>",
"<NSAutoresizingMaskLayoutConstraint:0x174288980 h=--& v=--& UITextField:0x10141f240.height == 30   (active)>",
"<NSAutoresizingMaskLayoutConstraint:0x17028dac0 h=--& v=--& UIButton:0x10131e3a0'Connect'.midY == 325.5   (active)>",
"<NSAutoresizingMaskLayoutConstraint:0x17028db10 h=--& v=--& UIButton:0x10131e3a0'Connect'.height == 45   (active)>",
"<NSLayoutConstraint:0x174287df0 V:[UITextField:0x10141f240]-(20)-[UIButton:0x10131e3a0'Connect']   (active)>"
)

Will attempt to recover by breaking constraint
<NSLayoutConstraint:0x174287df0 V:[UITextField:0x10141f240]-(20)-[UIButton:0x10131e3a0'Connect']   (active)>

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.

Upvotes: 2

Views: 1658

Answers (1)

thm
thm

Reputation: 1227

The problem here is that you don't turn off translatesAutoresizingMaskIntoConstraints on your widgets host, port, user, password and connectButton so for these, NSAutoresizingMaskLayoutConstraints will be generated which collide with your constraints.

You could for example insert this

for view in [host, port, user, password, connectButton] as [UIView] {
    view.translatesAutoresizingMaskIntoConstraints = false
}

into your viewDidLoad method, right after self.view.translatesAutoresizingMaskIntoConstraints = false.

You can also remove your attempts to consider your constraints at the end so your code will look like this:

override func viewDidLoad() {
    super.viewDidLoad()
    self.view.translatesAutoresizingMaskIntoConstraints = false
    for view in [host, port, user, password, connectButton] as [UIView] {
        view.translatesAutoresizingMaskIntoConstraints = false
    }
    host.centerXAnchor.constraint(equalTo:self.view.centerXAnchor).isActive = true
    host.topAnchor.constraint(equalTo:self.view.layoutMarginsGuide.topAnchor, constant:20.0).isActive = true
    port.centerXAnchor.constraint(equalTo:self.view.centerXAnchor).isActive = true
    port.topAnchor.constraint(equalTo:host.bottomAnchor, constant:20.0).isActive = true
    user.centerXAnchor.constraint(equalTo:self.view.centerXAnchor).isActive = true
    user.topAnchor.constraint(equalTo:port.bottomAnchor, constant:20.0).isActive = true
    password.centerXAnchor.constraint(equalTo:self.view.centerXAnchor).isActive = true
    password.topAnchor.constraint(equalTo:user.bottomAnchor, constant:20.0).isActive = true
    connectButton.centerXAnchor.constraint(equalTo:self.view.centerXAnchor).isActive = true
    connectButton.topAnchor.constraint(equalTo:password.bottomAnchor, constant:20.0).isActive = true
}

You will then realize that you might want to add a few width constraints on your (what I suppose are) text fields ;).

Anyways, if you prefer to deactivate translatesAutoresizingMaskIntoConstraints in Interface Builder, please see this answer on "Unexpected NSAutoresizingMaskLayoutConstraint adding UIView from nib to autolayout storyboard scene".

Upvotes: 1

Related Questions