Autolayout Problems with iOS8 with Code That Works Fine on iOS7

Issue with Auto Layout on iOS 8 (code works perfectly on iOS 7)

This is definitely an iOS 8 bug. I was able to work around it by sending setNeedsLayout to the container view (the superview of the image view).

I see that you're sending setNeedsLayout to self.view. If that code is in your view controller, then I guess self.view is not the container view. Try sending setNeedsLayout to the container view directly.

Demo project is here.

Sample Image

Auto-Layout Issues: iOS 7 vs iOS8

The issue was solved with answers from Stack-overflow. Basically, the right answer is this, but it was nicely summarized in this answer. The difference between iOS7 and iOS8 is not in the way the constraints are interpreted, but in the way that update commands are trickled down through the view hierarchy. When I implemented the behavior first in iOS 7, I noticed that the animation would only work properly if I called layoutIfNeeded on the parent view of the sizing view (i.e. on centering view). In iOS 7 this apparently trickled down the view hierarchy automatically. In iOS 8, this is not the case: You have to manually invalidate the view whose constraints have changed with setNeedsLayout, and then update the layout with layoutIfNeeded. My solution in the updated code looks like this:

- (IBAction)showLess:(id)sender {
self.widthConstraint.constant = 50;
[self.sizingView setNeedsLayout]; // *** THIS LINE IS NECESSARY TO MAKE THINGS WORK IN iOS 8
[UIView animateWithDuration:0.3 animations:^{
[self.sizingView layoutIfNeeded]; // trigger animation
}];
}

I've updated the question to include the answer, but in response to @unmircea I am posting a separate answer, as well.

Autolayout issue with core-data binding in iOS 8.1 but not in iOS 7

This issue appears to be the same as @Gallymon has in Autolayout problems with iOS8 with code that works fine on iOS7 and not the same as @BFar had in Issue with Auto Layout on iOS 8 (code works perfectly on iOS 7). I tried the suggested fix for Issue with Auto Layout on iOS 8 (code works perfectly on iOS 7), and it didn't work for me.

The ugly workaround I did was to create a transparent 1x1pt UIImageView (which I'll refer to as "anchorImage"), anchor its leading edge to the superview, and then anchor all the other widgets to the anchor image's trailing edge. I then need to readjust the horizontal location of the anchorImage if the device is rotated between portrait and landscape, but at least that is just one constraint I need to update instead of all of them.

I'm going to file a bug with Apple to have them investigate further.

If anyone sees something that I'm doing wrong and determines there's a better solution, I'm all ears...

I'm not marking this as the "correct" answer as maybe someone has a better idea.

UPDATE: Filed iOS bug 19108167 with Apple 12/1/14

iOS 8 Auto Layout issue

It's not a problem of Auto Layout, but must be a bug in iOS 8 about handling sliced image assets.

With your sample project:

    UIImage *img = [UIImage imageNamed:@"pointer-dark-left"];
NSLog(@"alignmentRect: %@", NSStringFromUIEdgeInsets(img.alignmentRectInsets));
NSLog(@"capInsets: %@", NSStringFromUIEdgeInsets(img.capInsets));

This code prints

// iOS 7
alignmentRect: {0, 0, 0, 0}
capInsets: {0, 5.5, 0, 134}

// iOS 8
alignmentRect: {0, 0, 0, 65.5}
capInsets: {0, 5.5, 0, 134}

alignmentRectInsets.right is 65.5!

As documented, Autolayout works with alignment rectangles, and UIImageView uses its images alignmentRectInsets. So, your self.line has 65.5pt extra right width.

Of course, you didn't set the Alignment Insets in xcassets editor, I believe it's a bug.

screenshot

Here is a ugly, but working, workaround :(

- (void)viewDidLoad {
[super viewDidLoad];
self.line.image = [self.line.image imageWithAlignmentRectInsets:UIEdgeInsetsZero];
}

iOS 7 vs iOS 8 autoloayout issues

Your constraints are overdetermined. I don't know why this issue doesn't emerge on iOS 8, but it is plain to see in the list of constraints in your screen shot what the problem is. In order, we have (I'll use the last two digits of the memory address of the views to identify them):

  • The top of view 80 -

    V:|-(0)-[UIView:0x7b099c80]
  • The height of view 80 -

    UIView:0x7b099c80.height == ...
  • The space between the bottom of view 80 and the top of view 60 -

    V:[UIView:0x7b099c80]-(0)-[UIView:0x7b099260]>
  • The height of view 60 -

    UIView:0x7b099260.height == ...
  • The bottom of view 60 -

    V:[UIView:0x7b099260]-(0)-[_UILayoutGuide:0x7b09a220]>

That's too many constraints. You can set the top and the height or the top and the bottom of something, but you must not set the top and the height and the bottom - because if the resulting arithmetic is off by even a tiny bit, those demands cannot be satisfied simultaneously.



Related Topics



Leave a reply



Submit