23
votes

One of the screens in my app completely broke when updating to the iOS 8 SDK. The problem seems to be that the top layout guide shifts up instead of being an 'anchor' for the rest of the views.

This is what the view looked like on iOS 7:

iOS 7 Screen

This is what it looks like in iOS 8 (captured from the Xcode 6 View Hierarchy debugger):

iOS 7 Screen

As you can see, the view appears way above the navigation bar. There are two constraints on the top layout guide, one for the upper image view, and one for the white view below it. There are no constraints on the bottom layout guide, only height constraints on the views.

For some reason, iOS 8 decides to push the top layout guide to {0 -255; 0 0} after [self.view layoutIfNeeded] is called for the first time. Also, the view's bounds sometimes appear too large for the device (i.e. showing up exactly as in the unified storyboard (600x600), instead of 320x480/320x568.

What has changed in iOS 8 that might screw up the layout?

[EDIT] Here is a complete list of the constraints on the view:

(lldb) po self.view.constraints
<__NSArrayM 0x786ac520>(
    <NSLayoutConstraint:0x7c377bd0 V:[_UILayoutGuide:0x7c372f60]-(0)-[UIView:0x7c373120]>,
    <NSLayoutConstraint:0x7c377c00 UIView:0x7c373120.width == UIView:0x7c3730b0.width>,
    <NSLayoutConstraint:0x7c377c30 UIView:0x7c3730b0.centerX == UIView:0x7c373120.centerX>,
    <NSLayoutConstraint:0x7c377c60 H:|-(0)-[UIView:0x7c3716f0]   (Names: '|':UIView:0x7c3730b0 )>,
    <NSLayoutConstraint:0x7c377c90 UIView:0x7c3716f0.width == UIView:0x7c3730b0.width>,
    <NSLayoutConstraint:0x7c372f30 V:[_UILayoutGuide:0x7c372f60]-(129)-[UIView:0x7c3716f0]>
)
5
Have you got this resolved?Mrunal
I know this is a lot to ask, but can you post a list of all the constraints? Sometimes they resolve themselves in weird ways, and it's hard to follow what's happening without seeing all of them.Anna Dickinson
I posted a list of all the constraints on the top-level view. I think that should suffice, because the entire view is shifted upwards... Let me know if you need more info!David Ganster
On the view's bounds sometimes appearing large; in viewDidLoad the bounds will still be whatever the storyboard sizes are (normally 600x600). The view's bounds will be correct in viewWillAppear and viewDidAppear, so save your frame/bounds updating code for those methods.keithbhunter
Have you filed a bug report on this?lensovet

5 Answers

43
votes

Extend Edges > Under Top Bars is checked by default in the Extend Edges section of the Attribute Inspector.

Try unchecking Under Top Bars.

This has helped me many times when I got strange behaviour like this.

Please note it's a UIViewController property, so you can set it in code if you'd like.

Under Top Bars option in Interface Builder

5
votes

You can either use UIBarPositionTopAttached or you can use view bounds and frames, i can also suggest and link you to Apple's documentation that would take some time for you to solve the issue.

The best and the most easiest way to solve this issue is to just embed your view controller inside a navigation controller and thats it. You can do it by just selecting the view controller and going to Editor > Embed In > Navigation Controller. (If there is any content on your old navigation bar, you can first drag it down, embed the view controller in navigation controller and then move the bar buttons on the new navigation bar and then delete the old navigation bar)

OR

Set the navigation bar's translucent property to NO:

self.navigationController.navigationBar.translucent = NO;

This will fix the view from being framed underneath the navigation bar and status bar.

If you have to show and hide the navigation bar, then use

 if ([self respondsToSelector:@selector(edgesForExtendedLayout)])
    self.edgesForExtendedLayout = UIRectEdgeNone;   // iOS 7 specific

in your viewDidLoad method.

Hope either of these will solve your issue.

5
votes

I'm using Xcode 6.3.1 and it seems the bug is back in that version (supposedly it was fixed in 5.1). I wasn't able to find a work-around on SO so I had to google some more and here it is:

instead of doing the usual Ctrl+drag in IB, just select the View you want to do this for and go to Editor -> Pin -> Top Space to Superview.

Here's the source: LINK It helped in my case.

2
votes

Also have a problem like that. If running on iOS8 only, you can change constraints from "topLayoutGuide.bottom-myView.top" to "topLayoutGuide.top-myView.top". But that will break UI for iOS7. It's possible to write workaround like that in code to support both versions, but there is no chance to make UI working well for both versions when creating UI in storyboards.

-4
votes

Instead of using the unified storyboard (600x600), you should keep one of the device resolutions for your interface builder and then layout your screen in IB.

If your view controller's size is 600x600 in storyboard, then in viewDidLoad, it will get that frame for your view controller's view and layout the subviews accordingly.

Hope this helps..