Trailing and Leading constraints in Swift programmatically (NSLayoutConstraints)

BlackBox picture BlackBox · Sep 27, 2016 · Viewed 45.8k times · Source

I'm adding from a xib a view into my ViewController. Then I'm putting its constraints to actually fit it

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    ...
    ...
    view!.addSubview(gamePreview)
    gamePreview.translatesAutoresizingMaskIntoConstraints = false
    if #available(iOS 9.0, *) {
        // Pin the leading edge of myView to the margin's leading edge
        gamePreview.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor).active = true
        //Pin the trailing edge of myView to the margin's trailing edge
        gamePreview.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor).active = true

    } else {
        // Fallback on earlier versions
        view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .TrailingMargin, relatedBy: .Equal, toItem: view, attribute: .TrailingMargin, multiplier: 1, constant: 0))

        view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .LeadingMargin, relatedBy: .Equal, toItem: view, attribute: .LeadingMargin, multiplier: 1, constant: 0))
    }
    view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Top, relatedBy: .Equal, toItem: self.topLayoutGuide, attribute: .Bottom, multiplier: 1, constant: 0))
    view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute,multiplier: 1, constant: 131))
}

What i'm trying to do: To actually fit my view constraining it to top, leading, trailing to ViewController's view, and with a prefixed height. The view I'm adding to main view has its own transparent-background view, so no need of margin (the view is meant to be device's width size, so).

I've placed 2 couples of lines that would be supposed to be equal (in my attempts), with the if, because the first 2 lines in if are actually available in iOS9> only, while I'm attempting to do the same thing in the else statement, for every device (starting from iOS 8).

This is what I get:

iOS9+ at left, iOS8+ at right. Transparent background was colored red to show what happens (don't mind at different height in the images, they're equal height in app, instead look at added margins at left and right)

I also tried AutoLayoutDSL-Swift, but doesn't help, I'm not expert with it but every attempt made only things worse.

How can I write those constraints using classic NSLayoutConstraints methods, and how could I write all in a better way with a framework like AutoLayoutDSL or a fork of it? (or an alternative, though now mostly I'm concerned on official libs)

Answer

Paulw11 picture Paulw11 · Sep 27, 2016

You need to use the leading and trailing attributes, not the leadingMargin and trailingMargin attributes:

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    ...
    ...
    view!.addSubview(gamePreview)
    gamePreview.translatesAutoresizingMaskIntoConstraints = false

    view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Trailing, relatedBy: .Equal, toItem: view, attribute: .Trailing, multiplier: 1, constant: 0))            
    view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Leading, relatedBy: .Equal, toItem: view, attribute: .Leading, multiplier: 1, constant: 0))

    view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Top, relatedBy: .Equal, toItem: self.topLayoutGuide, attribute: .Bottom, multiplier: 1, constant: 0))
    view.addConstraint(NSLayoutConstraint(item: gamePreview, attribute: .Height, relatedBy: .Equal, toItem: nil, attribute: .NotAnAttribute,multiplier: 1, constant: 131))
}