24

I'm in the midst of developing an app for the iPhone and iPad. It supports iOS6 and iOS7 and it uses auto layout exclusively.

This past week, when Apple announced that iOS8 was ready for prime-time, I upgraded one of my iPhones and an iPad both to iOS8. I also bumped my XCODE up to version 6. I have 2nd iPhone which I left at iOS7.

I generated new executables with Xcode 6 and I was distressed to see that their screen layouts were messed up when executed on my devices running iOS8 but still fine on iOS7. This is true on both my physical devices and on Xcode's emulators.

It took a lot of digging but I'm pretty clear now on what's happening though I don't know why.

Specifically, certain auto layout operations are failing for me on iOS8 but they are fine on iOS7.

Some examples involving a button which I am placing on an underlying view whose size is equal to the size of the screen:

(1) If I ask auto layout to position the button's horizontal center (CX) equal to the underlying view's horizontal center, the result is that the button's horizontal center is placed on the underlying view's left edge.

(2) If I ask auto layout to to make the width of the button equal to 50% of the width of the underlying view, it gives it no width at all.

I am able to work around these issues as follows:

(1) I ask auto layout to position the button's center equal to the underlying view's left edge plus 50% of the screen's width.

(2) I ask auto layout to make the button's width equal to 50% of the screen's width.

I am slowly clawing my way, with workarounds like these, back to auto layout code that works for me on both iOS7 and iOS8. But I am really wondering what's going on here.

It looks like auto layout cannot determine the size of the underlying view and so auto layout calculations that require that information fail. But it does know where the top and left edges of the view are so calculations based on those data succeed.

This is a large app and I've written many hundreds of lines of auto layout code for iOS6 and iOS7 that work perfectly for me.

I've been tweaking and trying things now with iOS8 for three days and I'm no wiser than I was when I began.

Anyone have any suggestions or thoughts as to what might be the issue here?

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
Gallymon
  • 1,557
  • 1
  • 11
  • 21
  • I'm on the same boat. Anyhow, it seems like your underlying view's width is 0 to begin width, hence when you told your button's center X to be the underlying view's center X, the button appears on the left edge. – Zhang Sep 23 '14 at 10:40
  • 1
    yes, and from what I can see so far, once I begin to place controls on the view, I can use all the different variations of auto layout relationships between those controls. I.e., one button's horizontal center can be aligned with another's with no problems. – Gallymon Sep 23 '14 at 17:02
  • I should mention as well that I am not using IB. All my auto layout code is done by constructing NSLayoutConstraint/s directly. Always have done it this way and it's worked perfectly in iOS7. – Gallymon Sep 23 '14 at 17:09
  • As an update, I am still working on this issue trying to get to the bottom of it. – Gallymon Sep 26 '14 at 16:13
  • I spent a week digging to see why valid auto layout on iOS<6|7> was failing on iOS8 and I came up with bupkis. I can see my constraints as I request my button to be centered in the superview and they are correct. But, regardless, iOS8 fails to place the button correctly. I've spent enough time on this and there are easy workarounds (as described above) so I'm going to drop it. | Shonky business, Apple. – Gallymon Oct 03 '14 at 01:50
  • 1
    See http://stackoverflow.com/questions/25954831/issue-with-auto-layout-on-ios-8-code-works-perfectly-on-ios-7#comment41054886_26066992 – smileyborg Oct 03 '14 at 17:24

3 Answers3

11

@robmayoff has a great answer for this: https://stackoverflow.com/a/26066992/1424669

Essentially, in iOS8 you can no longer call setNeedsUpdateConstraints and setNeedsLayout on a view and expect the constraints of subviews to update.

You must call these methods on the view whose constraint is changing. This is backwards compatible to iOS7.

EXAMPLE:

Suppose you have a ViewController with root view self.view and a subview called containerView. containerView has a NSLayoutConstraint attached to it that you want to change (in this case, top space).

In iOS7 you could update all constraints in a VC by requesting a new layout for the root view:

self.containerView_TopSpace.constant = 0;
[self.view setNeedsUpdateConstraints];
[self.view setNeedsLayout];

In iOS8 you need to request layouts on the containerView:

self.containerView_TopSpace.constant = 0;
[self.containerView setNeedsUpdateConstraints];
[self.containerView setNeedsLayout];
Community
  • 1
  • 1
BFar
  • 2,447
  • 22
  • 23
  • BFar, that's great news and makes good sense. I can't wait to try it out and see if I can put this problem behind me. – Gallymon Sep 27 '14 at 04:46
  • @BFar Can you please put together a simple sample project that demonstrates this issue (e.g. works on 7 SDK, but not on 8 SDK) and then file a radar and share the radar #? – smileyborg Sep 30 '14 at 16:23
  • BFar, I tried robmayoff's ideas but they do not seem to be related to my issue. I've got a legal workaround now so I'm pressing on. Thanks! – Gallymon Oct 03 '14 at 01:52
3

You might find the answers to this question helpful: UICollectionView cell subviews do not resize

In most cases the works in iOS7 but not on iOS 8 auto layout problems seem to stem from the root view not being sized correctly in iOS 8, particularly when we set translatesAutoresizingMaskIntoConstraints to NO. For my views I was able to set the root view's frame in layoutSubviews (or whichever appropriate initializer that does have the correct bounds) and this resolved the issue.

self.contentView.frame = CGRectInset(self.bounds, 0, 0);

As shown in the answer above, you could also do

self.contentView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;

and then turn translatesAutoresizingMaskIntoConstraints back to NO before you start setting your own constraints in code.

Definitely hate that so much of our time is taken with these annoying gotchas.

Community
  • 1
  • 1
Praneeth Wanigasekera
  • 946
  • 1
  • 10
  • 16
0

In my case, the problem related to constraints labeled UIView-Encapsulated-Layout-Width and UIView-Encapsulated-Layout-Height. When I removed them, everything behaved as though my view was of zero size, with everything centered on the upper left corner of the screen. When I left them in, new constraints worked as expected. I also retained the constraints labeled _UILayoutSupportConstraint.

Tad
  • 4,668
  • 34
  • 35