36

So I am doing some custom animations on my navigationcontroller and the way it pushes and pops the viewControllers.

Everything runs smooth. As soon as I add the following code (In a subclass of UINavigationController), I face a huge performance hit. After adding a shadow all animations become very laggy. Is this expected or am I doing something wrong in the code?

// This code gets called once during NavigationController initialization.
[self.view setClipsToBounds:NO];
[self.view.layer setCornerRadius:5];
[self.view.layer setShadowOffset:CGSizeMake(0, 20)];
[self.view.layer setShadowColor:[[UIColor yellowColor] CGColor]];
[self.view.layer setShadowRadius:20.0];
[self.view.layer setShadowOpacity:1];

EDIT:

Changed my shadow radius to 1 and it's still slow

aryaxt
  • 76,198
  • 92
  • 293
  • 442
  • 2
    For all it's worth, this is covered explicitly in WWDC 2010 Session 425: Core Animation in Practice, Part 2 [here.](https://developer.apple.com/devcenter/download.action?path=/videos/wwdc_2010__sd/session_426__core_image_effects_and_optimization.mov) – Chris Conover Mar 25 '14 at 04:59

6 Answers6

89
self.view.layer.shouldRasterize = YES;
self.view.layer.rasterizationScale = UIScreen.mainScreen.scale;

I was recently having some issues with slow CALayer shadows, and that simple line of code fixed up everything for me!

Maciej Swic
  • 11,139
  • 8
  • 52
  • 68
williamcotton
  • 1,129
  • 2
  • 7
  • 6
  • awesome, this makes it perform even better, now I can have any size of shadowRadius without having a performance hit – aryaxt May 01 '12 at 02:29
  • 24
    This will ignore the retina images that you may have for you annotation. To fix this, add the following line: self.view.layer.rasterizationScale = [UIScreen mainScreen].scale; – Sean Oct 25 '12 at 23:12
  • 2
    I'm having a similar issue with a tableView where each cell contains a few UILabels as well as a view with rounded corners. I added a shadow to the layer that contains the tableView and the scrolling becomes choppy. However, setting shouldRasterize = YES resolved the choppiness but pixelated the view (visibly blurry) so it's not an acceptable solution. I found using shadowPath instead of shadowOffset did the trick. – Alfie Hanssen May 25 '13 at 16:58
  • 1
    it could be worse if the view varies. shouldRasterize = YES is only a good solution when the view does not change, so bitmap is genereated once once and cached and reused by UIScrollView – ikzjfr0 Oct 24 '14 at 02:24
  • 1
    Please note that this increases your RAM usage – Maciej Swic Feb 02 '15 at 18:10
  • Awesome! Exactly what I was after! Thank you. – Nelly v Aug 01 '16 at 14:34
54

You should expect a slowdown from adding a shadow. A shadowRadius of 20 is very high and will be especially slow.

The other key to improve shadow rendering speed: set the shadowPath property. It can help dramatically.

Kurt Revis
  • 27,695
  • 5
  • 68
  • 74
  • setting ShadowPath did the trick, My shadow radius is 10 and it still performs well. – aryaxt Apr 03 '12 at 17:33
  • 3
    @NicolasManzini More tips for shadow performance: http://stackoverflow.com/questions/10133109/fastest-way-to-do-shadows-on-ios/10133182#10133182 – aryaxt Oct 11 '12 at 15:47
  • it's much efficient way that I test... idea with shouldRasterize work not so quick as it can be needed. this answer is much better! don't understand why @williamcotton answer gain so much votes... – Denis Kozhukhov Oct 14 '13 at 13:45
  • shadowPath did the trick. performance feels a million times better! – Liam Jun 19 '14 at 10:08
15

Using shadowPath instead of shadowOffset.

theView.layer.shadowPath = [UIBezierPath bezierPathWithRect:theView.bounds].CGPath;

Check this post: iphone - Animation's performance is very poor when view's shadow is on

Community
  • 1
  • 1
Bobo Shone
  • 721
  • 6
  • 16
  • Worked like a charm, better than shouldRasterize which blurred the view and all sublayers. – Alfie Hanssen May 25 '13 at 16:58
  • 1
    it's much efficient way that I test... idea with shouldRasterize work not so quick as it can be needed. this answer is much better! don't understand why @williamcotton answer gain so much votes... – Denis Kozhukhov Oct 14 '13 at 13:43
  • shadowPath is pretty good and fast, but how can keep update frame in autolayout? – TomSawyer Nov 28 '14 at 21:45
  • This is only if you don't have rounded corners or transparency in your views. Not every views is rectangular. `shouldRasterize` is more generic and we don't have to deal with any bezier paths as said. – chakrit May 04 '15 at 04:44
  • @TomSawyer do it in view's layoutSubviews, maybe you need subclass some views – ooops Jan 15 '17 at 17:18
2

Yes, shadow's are very expensive (especially a shadow that big -- play with the radius and you'll notice it makes a huge difference in the degree of slowdown you experience). One way to improve performance is to render it once to a CGImageContext and just display that image instead of having the layer re-render the shadow every time it redraws (but this doesn't work if the shadow needs to animate or something).

Ian Henry
  • 22,255
  • 4
  • 50
  • 61
  • You think it would perform better to use an actual png and add it to my UIView? – aryaxt Apr 03 '12 at 17:16
  • If that's a possibility (ie you know the shape/size/whatever of the shadow beforehand) then it would definitely give you better performance. Blitting images is much faster than rendering shadows. – Ian Henry Apr 03 '12 at 17:22
  • Prerendered to an image will work as long as yuo don't need to change the shadow shape. – Andres Canella Jul 08 '16 at 15:27
0

Swift 5.3. add this code.

myView -> UIView, collectionViewCell or tableViewCell can be.

myview.layer.shadowPath = UIBezierPath(rect: cell.bounds).cgPath
myview.layer.shouldRasterize = true
myview.layer.rasterizationScale = UIScreen.main.scale
ikbal
  • 1,110
  • 12
  • 21
0

I'm coding app with "Neumorphism" style, so much shadow and app so laggy. But use this code below, app very smooth.

viewHasShadow.layer.shouldRasterize = true
viewHasShadow.layer.rasterizationScale = UIScreen.main.scale
Dharman
  • 30,962
  • 25
  • 85
  • 135