I have an auto layout setup with an animation that alters a NSLayoutContraint constant value
// set the slide in view's initial height to zero
self.adViewHeightConstraint = [NSLayoutConstraint constraintWithItem:self.adContainerView
attribute:NSLayoutAttributeHeight
relatedBy:NSLayoutRelationEqual
toItem:nil
attribute:NSLayoutAttributeNotAnAttribute
multiplier:1.0
constant:0.0];
[self.view addConstraint:self.adViewHeightConstraint];
// later, set the slid in view's height to non-zero
double delayInSeconds = 3.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
self.adViewHeightConstraint.constant = 100;
[UIView animateWithDuration:2.5 animations:^{
[self.view layoutIfNeeded];
}];
});
This correctly animated the sizes of the views I have and thus, works correctly. The problem I am seeing, however, is that some custom layer backed views I have are not being redrawn over the duration of the 2.5 sec animation.
The behavior I am seeing is that the custom layer backed views are asked to draw for the final position at the beginning of the animation, then a transform is applied that stretches the view over the duration of the animation until it eventually looks correct.
What these 4 shots show is the red bar animating up, then the two blue views shrinking in height each to accommodate the size reduction. The layer knows how to draw itself correctly for each bounds change, but the animation is not asking it to redraw at each step of the animation... only at the beginning. This is why the black circle looks like an oval — it is the same 2 halves as image #4 but stretched.
The custom CAlayer
subclass has one overridden method: drawInContext:
, and the layer has needsDisplayOnBoundsChange
set to YES
.
Thus, the question remains... How can I tell this animation of NSLayoutConstraints
to let the views redraw during the entire animation?
This is a known issue (if you google it you'll see a couple of good hits, though I think this answer, while admittedly focusing of different symptoms, is the most articulate answer I've seen thus far describing the problem UIView scaling during animation ... it's an old answer, but still applicable, I believe).
The easiest solution, IMHO, would be to put the layer in a view that doesn't resize upon animation (e.g. a new view, of fixed size, whose constraints keep it centered on your content view, but doesn't change size as your content view does). That way, you can enjoy the constraints-based animations, but not lose your custom layer's aspect ratio/size.