Anchor Constraints Not Honored in Xcode 10/iOS 12

Anchor Constraints not Honored in Xcode 10 / iOS 12

I posted what seems to be the answer in my second update, but for clarity:

I added a self.layoutIfNeeded() just after applying the anchor constraints and that seems to have solved the issue. Although looking at the frame for self and I get -199,-100,398,200 Cannot say I understand the values for X and Y. Nevertheless the layOutIfNeeded seems to have solved the problem although why this is required in Xcode 10/ iOS 12 is also a mystery.

iOS Constraints Not Updating After Setting Programatically

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".

Why is NSLayoutConstraint's identifier property not working in code?

I think in your situation it's better to keep the bottom constraint and just update the constant later on, when needed, like this:

class PDFViewer: UIViewController {
var quickLookController = QLPreviewController()
var bottomConstraint: NSLayoutConstraint?

override func viewDidLoad()

if let quickView = quickLookController.view {
self.view.addSubview(quickView)
}

quickLookController.view.translatesAutoresizingMaskIntoConstraints = false
bottomConstraint = quickLookController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
NSLayoutConstraint.activate([
quickLookController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
quickLookController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
quickLookController.view.topAnchor.constraint(equalTo: navView.bottomAnchor),
bottomConstraint
])

setPDFViewHeight(height: 100)
setPDFViewHeight(height: 100)


open func setPDFViewHeight(height: CGFloat) {
bottomConstraint.constant = height
}
}

Also the naming of the setPDFViewHeight may be misleading, because what it really does is that it set's the offset from the anchor, not the absolute height.

NSLayoutconstraints not working as expected

translatesAutoresizingMaskIntoConstraints is not set to false for your closureInfoLabel and closeRequestTitleLabel.

Getting Warning for UI Layout in iOS Unable to simultaneously satisfy constraints

This is a common situation when using cells with embedded views.

As you've seen, the UI result looks fine -- because auto-layout will attempt to recover by breaking constraint, and then it re-establishes the constraint.

To get rid of the warnings, give the constraint that ends up defining the height a less-than-required priority.

So, change the end of your setupView() func to this:

    if let lastView = contentHolderView.getTheLastAddedView() {
let c = lastView.bottomAnchor.constraint(equalTo: contentHolderView.bottomAnchor, constant: -20)
c.priority = .required - 1
c.isActive = true
//lastView.bottomAnchor.constraint(equalTo: contentHolderView.bottomAnchor, constant: -20).isActive = true
}

// this is not needed
//self.layoutIfNeeded()

As a side note, a cell's subviews should not be added to, or constrained to, the cell itself. You should use the cell's .contentView instead:

    contentView.addSubview(contentHolderView)

and then:

    NSLayoutConstraint.activate([
//layout contentView
contentHolderView.topAnchor.constraint(equalTo: contentView.topAnchor,constant: 0),
contentHolderView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor,constant: 0),
contentHolderView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor,constant: 0),
contentHolderView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor,constant: 0),

Auto Layout constraint crashes due to anchor in a different view hierarchy in iOS, but

I was able to identify what causes the crash.

The only difference in the last commit is a small delay (before adding the UI elements and the constraints). 0.01 seconds are enough and it works fine as follows:

import UIKit
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.title = "APP TITLE"
self.view.backgroundColor = .white
Timer.scheduledTimer(withTimeInterval: 0.01, repeats: false) { (nil) in
let navBar = self.navigationController!.navigationBar
let label = UILabel()
label.backgroundColor = .yellow
label.text = "TEXT"
label.textAlignment = NSTextAlignment.center
self.view.addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.widthAnchor.constraint(equalToConstant: 50).isActive = true
label.heightAnchor.constraint(equalToConstant: 20).isActive = true
label.centerXAnchor.constraint(equalTo: label.superview!.centerXAnchor).isActive = true
label.topAnchor.constraint(equalTo: navBar.bottomAnchor, constant: 10).isActive = true
}
}
}

You will find a clean Xcode project with the working code here https://www.dropbox.com/s/vhd9emd8ixf5lbs/AutoLO.zip?dl=0

Comment the Timer.scheduledTimer(withTimeInterval: repeats:) lines and it will crash with the message:

*** Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to activate constraint with anchors NSLayoutYAxisAnchor:0x60c000267e80 "UILabel:0x7fe0ede0b960'TEXT'.top" and NSLayoutYAxisAnchor:0x60c000267f00 "UINavigationBar:0x7fe0edd06ce0.bottom" because they have no common ancestor. Does the constraint or its anchors reference items in different view hierarchies? That's illegal.

The explanation of why Xcode complains about a centerY / YAxis anchor when there is none, is a mystery to me.

IOS SafeAreaLayoutGuide anchor for landscape screen

For label5 you should change a bottom constraint to:

label5.bottomAnchor.constraint(lessThanOrEqualTo: view.safeAreaLayoutGuide.bottomAnchor, constant: -10.0).isActive = true

It should be a negative number since you fix it to the anchor, which is below (in contrast to previous anchors where you fix it to the label above your current one). And for negative numbers you need to use lessThanOrEqualTo.

For the vertical layout it works fine too since constraint is lessThanOrEqualTo:



Related Topics



Leave a reply



Submit