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.
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.5
pt extra right width.
Of course, you didn't set the Alignment Insets in xcassets
editor, I believe it's a bug.
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
How to Reference Instance Function When Calling Sequencetype.Foreach
Error When Trying to Call Setdata(From: ) in the Cloud Firestore iOS API. How to Fix It
How to Disable the Network in iOS Simulator
Specifying One Dimension of Cells in Uicollectionview Using Auto Layout
Count Unseen Messages with Firebase in Swift
How to Store Push Notification Alert Message in Userdefault
Swift - Using Replacerange() to Change Certain Occurrences in a String
Different Font Size for Different Devices in Xcode 6
Selector to Get Indexpath Uicollectionview Swift 3.0
Retain Cycle (Strong Reference) Fix for Custom Uitextfield
Swift Formatting String to Have 2 Decimal Numbers If It Is Not a Whole Number
Firebase Fcm Silent Push Notifications for iOS
Checking a Null Value in Objective-C That Has Been Returned from a JSON String