Search code examples
iosuiviewcore-animationcalayershadow

Smoothly rotate and change size of UIView with shadow


I have a UIView with a shadow and a UIImageView subview.

I want to resize the view when the iPad is rotated and I'm trying to do this in the willRotateToInterfaceOrientation callback.

If I set the shadow on the UIView in the basic way the rotation is very choppy; so I'd like some suggestions from others on how to set the shadow setting layer.shadowPath.

I have tried animating the frame size change using [UIView animateWithDuration:animations] and setting the new shadowPath in the same block, but the shadow path snaps to the new size.

And if I don't change the layer's shadowPath in the animations block, it doesn't change.

From a few searches I've done, animating changes to layer properties need to be done with a CABasicAnimation.

So I think the question may be "how do I animate a UIView's frame size and layer change simultaneously?"


Solution

  • There's a bit more code than one would hope but something like this should work.

      CGFloat animationDuration = 5.0;
    
      // Create the CABasicAnimation for the shadow
      CABasicAnimation *shadowAnimation = [CABasicAnimation animationWithKeyPath:@"shadowPath"];
      shadowAnimation.duration = animationDuration;
      shadowAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; // Match the easing of the UIView block animation
      shadowAnimation.fromValue = (id)self.shadowedView.layer.shadowPath;
    
      // Animate the frame change on the view
      [UIView animateWithDuration:animationDuration
                            delay:0.0f
                          options:UIViewAnimationCurveEaseInOut
                       animations:^{
                         self.shadowedView.frame = CGRectMake(self.shadowedView.frame.origin.x,
                                                              self.shadowedView.frame.origin.y,
                                                              self.shadowedView.frame.size.width * 2.,
                                                              self.shadowedView.frame.size.height * 2);
                       } completion:nil];
    
      // Set the toValue for the animation to the new frame of the view
      shadowAnimation.toValue = (id)[UIBezierPath bezierPathWithRect:self.shadowedView.bounds].CGPath;
    
      // Add the shadow path animation
      [self.shadowedView.layer addAnimation:shadowAnimation forKey:@"shadowPath"];
    
      // Set the new shadow path
      self.shadowedView.layer.shadowPath = [UIBezierPath bezierPathWithRect:self.shadowedView.bounds].CGPath;