1
votes

Within my iOS app, I have a that needs to be animated, transformed with gestures, shaded (using shadows), and edited. When I perform animations and gestures on this UIView it is extremely "laggy". The animations aren't very "laggy" on the iPhone, however when using the iPad the animations become almost unresponsive (to the point where it seems like my app is crashing). I've tested my app using Instruments, and the app isn't taking up much memory / CPU / power until the animations begin. I have tested both on the device and on my Intel i7 8GB iMac and the animations are "laggy" on both.

The animation I am performing is nothing complex, it is simply a translation across the X Axis. After looking through every line of code related to the animation, I found that these lines are the issue(s):

viewer.layer.masksToBounds = NO;
viewer.layer.shadowOffset = CGSizeMake(-1, 1);
viewer.layer.shadowRadius = 3;
viewer.layer.shadowOpacity = 0.3;

The above code adds a shadow to the view that lags whenever I animate it (viewer). If I use the above code, but I add the following line animations work nicely:

viewer.layer.shouldRasterize = YES;

The problem with this code is that is seriously decreases the quality of the content displayed inside of the UIView (viewer). Here's an image with shouldRasterize set to YES:

UIView with Rasterization

Then the UIView without shouldRasterize:

UIView without Rasterization

Those screenshots are both from the same Retina iPad.

The ultimate question: How can I smoothly perform animations on a UIView with shadows (preferably using QuartzCore)? Is there a way to rasterize the content without degrading its quality?

1

1 Answers

3
votes

The shadow properties on CALayer can be very inefficient while animating because it requires recalculating the shadow on every frame based on the contents of the layer. Luckily, the expensive part is the shadow path calculation, so if you just create a CGPath representing the shape of your content and assign it to layer.shadowPath then performance will skyrocket.

Since your layer seems to be completely filled with opaque data, the shadowPath is pretty simple:

layer.shadowPath = [UIBezierPath bezierPathWithRect:(CGRect){CGPointZero, layer.bounds.size}].CGPath;

The only downside is you'll need to edit this whenever the size of the layer changes.