问题
I'm having trouble getting my view to lay itself out properly after modifying a second constraint (the first works fine). I'm modifying one constraint, animating it, and then modifying another constraint in the completion block (without animation).
My reason for doing this is I don't want the second constraint change to affect the animation, but I want it to instantly take effect as soon as the initial animation completes.
The problem is the second constraint change is simply not taking effect, no matter what I try.
Here's what I'm trying (note the problem is only when toolbarVisible
is YES
, as I perform both animations up front when it is NO
):
if ( !toolbarVisible )
self.containerViewBottomSpace.constant = toolbarVisible ? 60.f : 0;
self.toolbarBottomSpace.constant = toolbarVisible ? 0 : 60.f; // this one works fine
[self.view setNeedsUpdateConstraints];
[UIView animateWithDuration:0.3f animations:^{
[self.view layoutIfNeeded];
} completion:^(BOOL finished) {
if ( toolbarVisible )
self.containerViewBottomSpace.constant = 60.f; // this one is not taking effect
[self.view setNeedsUpdateConstraints];
[self.view layoutIfNeeded];
}];
The above method takes place inside an observeValueForKeyPath:...
method. I've tried wrapping the whole above code in a dispatch_after
block, but that has an even worse effect in that it is always one step behind (i.e. containerView is always in the opposite position as it should be) as if the second constraint modification isn't taking effect until the next animation.
Similarly, if I push another view onto the navigation controller (which is embedded inside the containerView), the layout corrects itself. It's as though it's just ignoring my command to lay itself out again for some reason.
Actually I just noticed that even if I make the second change initially and skip the completion block altogether, it doesn't appear to be animating the second constraint change in all cases. Something is fishy.
Update: I was using dispatch_after
incorrectly thinking it accepted an NSTimeInterval. After giving it a proper dispatch_time_t
and putting it inside the completion block, the layout is now sometimes updating. However, it's very flaky and this seems very hackish so I feel as though I'm missing something. If anyone knows more about this please enlighten me and I'll give you the answer.
Update 2: I decided to try logging the height of the element I am trying to change in viewDidLayoutSubviews
. Interestingly, it gets called twice, first with the previous value and second with the correctly adjusted height. So I guess it is at least partially laying things out correctly, but for some reason the tableView that is inside the containerView is still not resizing itself properly. I'm not sure what I'm missing.
回答1:
I'd first breakpoint and make sure you're not hitting the animation code a second time during the animation duration. If it's in observeValueForKeyPath you could hit the animation multiple times and it causes some inconsistency.
You also shouldn't need to call setNeedsUpdateConstraints or layoutIfNeeded. Setting the constant should be enough.
I'd also make sure that you've got the constraints wired up correctly and toolbarVisible is true.
来源:https://stackoverflow.com/questions/23962936/view-not-updating-when-autolayout-constraint-modified-programmatically