2

I have the following code to simply center a red square using AutoLayout constraints programmatically in my ViewController's view:

class ViewController: UIViewController {

    let square: UIView

    required init?(coder aDecoder: NSCoder) {
        let squareFrame = CGRectMake(0.0, 0.0, 500.0, 500.0)
        self.square = UIView(frame: squareFrame)

        super.init(coder: aDecoder)
    }

    override func viewDidLoad() {
        self.view.addSubview(self.square)
        self.square.backgroundColor = UIColor.redColor()
        self.view.backgroundColor = UIColor.blueColor()
        print(self.square)
        setupConstraints()
        print(self.square)
    }


    func setupConstraints() {
        self.square.translatesAutoresizingMaskIntoConstraints = false

        NSLayoutConstraint(item: self.view, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal,
            toItem: self.square, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant:0).active = true
        NSLayoutConstraint(item: self.view, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal,
            toItem: self.square, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant:0).active = true
    }
}

The resulting screen however only shows the blue background, no sign of the red square... Even when using the view debugging feature in Xcode it can't be seen.

enter image description here

If I comment out setupConstraints(), it works as "expected" with the original frame that I gave the square during initialisation.

By the way, both print statements have the exact same output: <UIView: 0x7ff1c8d3f3e0; frame = (0 0; 500 500); layer = <CALayer: 0x7ff1c8d04c00>>

How can this be when the square is nowhere to be seen?

Update: The issue remains when I am adding width and height constraints as suggested by @HaydenHolligan in setupConstraints():

func setupConstraints() {
    self.square.translatesAutoresizingMaskIntoConstraints = false

    NSLayoutConstraint(item: self.view, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal,
        toItem: self.square, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant:0).active = true
    NSLayoutConstraint(item: self.view, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal,
        toItem: self.square, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant:0).active = true

    // the following lines have no effect with respect to the issue mentioned aboove
    let sizeFormat = "[square(100@100)]"
    let size = NSLayoutConstraint.constraintsWithVisualFormat(sizeFormat, options: NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: ["square": self.square])
    self.view.addConstraints(size)
}
nburk
  • 22,409
  • 18
  • 87
  • 132
  • 2
    Just for fun, try adding two more constraints for height and width – Hayden Holligan Dec 08 '15 at 17:10
  • thanks for the suggestion, it doesn't seem to help though... adding constraints for width/height has no effect (at least when added in the way I showed in the updated question, do you know another one?) @HaydenHolligan – nburk Dec 08 '15 at 17:15
  • `[square(100@100)]` does not define a 100 x 100 size, but a 100 pixel width with a 100 priority – jcaron Dec 08 '15 at 17:21
  • Note also that contraints are now applied immediately when you add them, but only once your code surrenders to the run loop, so logging the size right away won't show the actual size it will have once the constraints have been applied. – jcaron Dec 08 '15 at 17:22
  • I meant something like `NSLayoutConstraint(item: self.view, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: self.view, attribute: NSLayoutAttribute.Height, multiplier: 1, constant:100).active = true`. Sometimes with auto layout if height/width constraints aren't set the view gets squished to 0. Not sure if this is the case – Hayden Holligan Dec 08 '15 at 17:27
  • all right, I tried Oleg's answer and it does indeed work. so, the lack of width and height constraints were the actual issue! it makes sense to me now as the constraints got applied but the square's size was decreased to `(0,0)` which made it "disappear". – nburk Dec 08 '15 at 17:41
  • 1
    darn, i should've answered the question instead of commenting :p – Hayden Holligan Dec 08 '15 at 17:48

1 Answers1

6

Try to change your setupConstraints func to this :

func setupConstraints() {

    self.square.translatesAutoresizingMaskIntoConstraints = false

    let centerX = NSLayoutConstraint(item: self.view, attribute: NSLayoutAttribute.CenterX, relatedBy: NSLayoutRelation.Equal,toItem: self.square, attribute: NSLayoutAttribute.CenterX, multiplier: 1, constant:0)
    let centerY = NSLayoutConstraint(item: self.view, attribute: NSLayoutAttribute.CenterY, relatedBy: NSLayoutRelation.Equal,toItem: self.square, attribute: NSLayoutAttribute.CenterY, multiplier: 1, constant:0)
    let squareWidth = NSLayoutConstraint(item: self.square, attribute: NSLayoutAttribute.Width, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant:500)
    let squareHeight = NSLayoutConstraint(item: self.square, attribute: NSLayoutAttribute.Height, relatedBy: NSLayoutRelation.Equal, toItem: nil, attribute: NSLayoutAttribute.NotAnAttribute, multiplier: 1, constant:500)

    self.view.addConstraints([centerX , centerY ,squareWidth , squareHeight])

}
Oleg Sherman
  • 2,772
  • 1
  • 21
  • 20
  • 1
    Just beat me. @nburk by the way, your print statements are in the wrong place. Setting constraints and doing layout are two different operations. Setting a constraint on a view doesn't change its layout on the spot. If you want to check the frame of a view **after** layout then override viewDidLayoutSubviews and put your prints there. – Aurast Dec 08 '15 at 17:38
  • ah.. that makes sense! thanks for the additional info though @rschmidt – nburk Dec 08 '15 at 17:39
  • 1
    DO NOT USE `addConstraints` because of this: `public func addConstraints(constraints: [NSLayoutConstraint]) // This method will be deprecated in a future release and should be avoided.  Instead use +[NSLayoutConstraint activateConstraints:].` And remember that the first item should be the item you want to put constraints on, while the second item is the reference for the constraints. – DevAndArtist Dec 08 '15 at 19:31