1

What am I missing re: Auto Layout and this simple example?

Using xcode 6.2 with the single view template for iOS, my storyboard looks like this:

interface builder main storyboard

I have a view controller with a scrollview that consumes the available space. No constraints are set from interface builder on the scrollview so it should be translating the auto resizing mask to constraints.

When I run this in the simulator I get the following output. Note the measurements output in the console. I have obtained these measurements in both viewDidLayoutSubviews and viewDidAppear they were the same in both cases. Also, for this example I have had Adjust Scroll View Insets enabled and disabled with the same result:

Adjust Scroll View Insets v1

Adjust Scroll View Inserts v2

The rendered result is:

Rendered Result 1

Note the frame and bounds size in the console for the scrollview: 600x600. Additionally, there is a very noticeable white gap at the bottom of the view. This does not line up with the Storyboard layout. It should be filling the view. So I can only assume that, in the storyboard, the size class is set to 600x600 and the auto layout constraints get translated from that.

Fair enough, lets turn them off, in viewDidLoad I did the following with the assumption that the resulting frame would be 0x0 if I did not set any additional constraints:

view.setTranslatesAutoresizingMaskIntoConstraints(false)    
scrollView.setTranslatesAutoresizingMaskIntoConstraints(false)

Nothing happened, the view rendered the same as above, not with 0x0 dimensions as I assumed but with 600x600. Clearly my assumption was wrong.

Next I tried adding constraints myself with:

view.setTranslatesAutoresizingMaskIntoConstraints(false)    
scrollView.setTranslatesAutoresizingMaskIntoConstraints(false)

Still present. My next run in the simulator, I got a lot of output telling me that there were conflicting constraints. Specifically there were 2 in question that I did not set: NSIBPrototypingLayoutConstraint That made me think that clearly setTranslatesAutoresizingMaskIntoConstraints is being ignored?

I found this reference to the same issue:

https://stackoverflow.com/a/18995528/1060314

Ok, so there are some constraints, I will remove all of the constraints and try setting them myself again manually, I will also omit setTranslatesAutoresizingMaskIntoConstraints:

// there should be no need to set the translates auto resizing mask
// to false, as I'm removing everything anyway.
view.removeConstraints(view.constraints())

var h1 = NSLayoutConstraint.constraintsWithVisualFormat("H:|[view]|",
    options: NSLayoutFormatOptions(0), metrics: nil, views: ["view": scrollView])

var v1 = NSLayoutConstraint.constraintsWithVisualFormat("V:|[view]|",
    options: NSLayoutFormatOptions(0), metrics: nil, views: ["view": scrollView])

view.addConstraints(h1 + v1)

This generated the expected output:

Rendered Result 2

There is no gap, at the bottom, the log output is correct as well.

I can receive the same result if I set the constraints in interface builder. I assume settings constraints in IB removes the NSIBPrototypingLayoutConstraints?

Interface Builder Constraints 1

Interface Builder Constraints 2

So I really am left with not understanding what's going on here. I mean I guess I understand why my final example gave me what I expected. I deleted all the constraints and set them up myself; that makes sense. Or I used Interface Builder to do the same as the code above.

What I clearly don't understand is what Interface Builder is doing with it's automatically generated constraints of type NSIBPrototypingLayoutConstraint, and why setting setTranslatesAutoresizingMaskIntoConstraints appears to do nothing about them.

Is this just a bug?

Community
  • 1
  • 1
AJ Venturella
  • 4,742
  • 4
  • 33
  • 62

1 Answers1

1

When you create a view without any constraints, Interface Builder warns you:

The selected views have no constraints. At build time, explicit left, top, width, and height constraints will be generated for the view.

enter image description here

For your purposes, the automatically generated left and top constraints of zero are fine. But the automatically generated width and height constraints of 600 are not. If you want it to use top/bottom and leading/trailing constraints, then you should add them yourself.

Alternatively, if you choose "Reset to suggested constraints", even those are better than the 600x600 constraints it will generate in the absence of any constraints:

enter image description here

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • 1
    Yes, but that still doesn't explain why the `setTranslatesAutoresizingMaskIntoConstraints(false)` is ignored. I'm going to accept your answer as I have come to the conclusion that you should always set your constraints lest you get some unexpected behavior. – AJ Venturella Mar 22 '15 at 02:46
  • Because it's not using `translatesAutoresizingMaskIntoConstraints`. Look at the value of `translatesAutoresizingMaskIntoConstraints` and it's already `false`. It's not using that feature, but rather it's using constraints that it added for you. – Rob Mar 22 '15 at 02:56
  • 1
    Ah, this also helps to kill those Prototype Constraints: [Intrinsic Size: Placeholder](https://dl.dropboxusercontent.com/u/20065272/forums/autolayout_uiscrollview/intrinsic_size.jpg) – AJ Venturella Mar 22 '15 at 03:31