This has been driving me crazy. I am using s CATransform3D
to animate the main layer of my view (to apply a perspective effect). I have a function called ApplyPerspective
that sets it up, and ClearPerspective
which resets the layer's transform property to CATransform3DIdentity
.
Here's my code:
ApplyPerspective(self.mainContentView);
[UIView animateWithDuration:self.animationDuration
delay:0.0
options:UIViewAnimationOptionCurveEaseOut
animations:^{
ClearPerspective(self.mainContentView);
}
completion:nil];
The issue I am having is that the perspective transform applied by ApplyPerspective
is incorrect. If I remove the -animateWithDuration
call, but leave the ApplyPerspective
call, the layer is rendered as expected. I am not sure why the behavior is changing when animated.
I have tried changing the duration, animation curve, flattening the function calls, but I am unable to trace the source of this error.
Update to add bodies of ApplyPerspective() and ClearPerspective():
void ApplyPerspective(UIView *aView) {
// Magic numbers derived using debug sliders
CGFloat zDist, rotRads, xOffset, yOffset, scale, shift;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
zDist = 172.5378;
rotRads = 2.6531;
xOffset = -13.0;
yOffset = 402;
shift = -241;
}
else {
zDist = 513.4995;
rotRads = 1.0007;
xOffset = 0.0;
yOffset = -100.0;
scale = 1.0;
shift = 0.0;
}
CATransform3D p = CATransform3DIdentity;
p = CATransform3DTranslate(p, xOffset, yOffset, 0.0);
p.m34 = 1.0 / -zDist;
p = CATransform3DRotate(p, rotRads, 1.0, 0.0, 0);
p = CATransform3DTranslate(p, 0, shift, 0.0);
aView.layer.transform = p;
}
void ClearPerspective(UIView *aView, UIView *parentView) {
aView.layer.transform = CATransform3DIdentity;
}
Here's the view hierarchy: mainContentView is a child of the ViewController's root view, which uses auto layout. The constraints are such that mainContentView fills the root view. mainContentView has a sibling image view which is used as a background during the animation.
I finally solved it! Apparently some transforms can affect auto layout, and the frame of mainContentView
was being modified by the layout engine, even though the transform was being reset to the identity transform.
The fix is to send -layoutIfNeeded
to the parent view (self.view
in my case) to force layout, and again after the animation is complete. I am posting this since others may run into something similar.
If your transforms aren’t looking right, send -layoutIfNeeded
.