问题
I am trying to create a collapsible toolbar that works like this (running in iOS 7 -- ugly colors etc. for visualization purposes):
However, when I run the code in iOS 8, this is what happens:
I have set up a constraint system that is based on the following:A centering view
(not shown) keeps the toolbar in the screen middle.
A sizing view
is adjusted to collapse the toolbar. The sizing view
is anchored to the right of the centering view
(via a trailing
constraint).
A container view
holds the actual content of the toolbar. It is anchored to the right of the sizing view
(also via a trailing
constraint).
Various content views
are contained in the container view
. They have no constraints. The default constraints applied by the system should be width, height, top, left, which ensures that they keep their relative positions in the container view
.
The collapsing of the toolbar is achieved as follows:
- (IBAction)showLess:(id)sender {
self.widthConstraint.constant = 50; // adjust this number for collapse / expand
[UIView animateWithDuration:0.3 animations:^{
[self.centeringView layoutIfNeeded]; // trigger animation
}];
}
Which adjusts the width of the sizing view
.
Problem: iOS 8 seems to behave as if I had left anchored the content view, but this is not true.
I would sincerely appreciate:
- An explanation as to why iOS 8 would have such a radically different interpretation of the given (reasonably simple) constraints.
- A pointer as to how I can get the intended behavior in iOS 8
Source code available here (updated version that works in iOS 8).
UPDATE:
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 hope this helps others who are also stuck on this forward compatibility issue.
回答1:
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.
来源:https://stackoverflow.com/questions/26770852/auto-layout-issues-ios-7-vs-ios8