CALayer - Shadow causes a performance hit?

19,536

Solution 1

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.

Solution 2

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!

Solution 3

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

Solution 4

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).

Share:
19,536

Related videos on Youtube

aryaxt
Author by

aryaxt

Updated on May 11, 2021

Comments

  • aryaxt
    aryaxt about 3 years

    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

    • Chris Conover
      Chris Conover about 10 years
      For all it's worth, this is covered explicitly in WWDC 2010 Session 425: Core Animation in Practice, Part 2 here.
  • aryaxt
    aryaxt about 12 years
    You think it would perform better to use an actual png and add it to my UIView?
  • Ian Henry
    Ian Henry about 12 years
    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.
  • aryaxt
    aryaxt about 12 years
    setting ShadowPath did the trick, My shadow radius is 10 and it still performs well.
  • aryaxt
    aryaxt about 12 years
    awesome, this makes it perform even better, now I can have any size of shadowRadius without having a performance hit
  • aryaxt
    aryaxt over 11 years
    @NicolasManzini More tips for shadow performance: stackoverflow.com/questions/10133109/…
  • Sean
    Sean over 11 years
    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;
  • Alfie Hanssen
    Alfie Hanssen almost 11 years
    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
    Alfie Hanssen almost 11 years
    Worked like a charm, better than shouldRasterize which blurred the view and all sublayers.
  • Denis Kozhukhov
    Denis Kozhukhov over 10 years
    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
    Denis Kozhukhov over 10 years
    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...
  • Liam
    Liam almost 10 years
    shadowPath did the trick. performance feels a million times better!
  • ikzjfr0
    ikzjfr0 over 9 years
    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
  • TomSawyer
    TomSawyer over 9 years
    shadowPath is pretty good and fast, but how can keep update frame in autolayout?
  • Maciej Swic
    Maciej Swic over 9 years
    Please note that this increases your RAM usage
  • chakrit
    chakrit about 9 years
    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.
  • Andres Canella
    Andres Canella almost 8 years
    Prerendered to an image will work as long as yuo don't need to change the shadow shape.
  • Nelly v
    Nelly v almost 8 years
    Awesome! Exactly what I was after! Thank you.
  • ooops
    ooops over 7 years
    @TomSawyer do it in view's layoutSubviews, maybe you need subclass some views