Fastest way to do shadows on iOS?

前端 未结 2 840
执笔经年
执笔经年 2020-12-07 08:27

QuartzCore .layer.shadow\'s suck up performance. They appear to need to be re-rendered every time something changes, causing everything to lag.

Coregraphics gradient

相关标签:
2条回答
  • 2020-12-07 08:43

    I've often seen people using the HUGE performance impact view's layer to create a rounded corner or dropshadow. Something like this:

    [v.layer setCornerRadius:30.0f];
    [v.layer setBorderColor:[UIColor lightGrayColor].CGColor];
    [v.layer setBorderWidth:1.5f];
    [v.layer setShadowColor:[UIColor blackColor].CGColor];
    [v.layer setShadowOpacity:0.8];
    [v.layer setShadowRadius:3.0];
    [v.layer setShadowOffset:CGSizeMake(2.0, 2.0)];
    .....
    

    This has a HUGE performance impact, especially with the shadow. Putting views like this in a UITableView (or matter fact anything that moves) will create an android-ish scrolling experience, you do not want that. If you need to animate or move the view, avoid creating rounded corners or drop shadows like this by any means!

    Meet Core Graphics
    I've created a simple UIView subclass to show you how to achieve the same result in a slightly different way. It uses Core Graphics to draw the view and in contrast to the code above, it does not impact the performance.

    Here's the drawing code:

    - (void)drawRect:(CGRect)rect
    {
       CGContextRef ref = UIGraphicsGetCurrentContext();
    
      /* We can only draw inside our view, so we need to inset the actual 'rounded content' */
      CGRect contentRect = CGRectInset(rect, _shadowRadius, _shadowRadius);
    
      /* Create the rounded path and fill it */
      UIBezierPath *roundedPath = [UIBezierPath bezierPathWithRoundedRect:contentRect cornerRadius:_cornerRadius];
      CGContextSetFillColorWithColor(ref, _fillColor.CGColor);
      CGContextSetShadowWithColor(ref, CGSizeMake(0.0, 0.0), _shadowRadius, _shadowColor.CGColor);
      [roundedPath fill];
    
      /* Draw a subtle white line at the top of the view */
      [roundedPath addClip];
      CGContextSetStrokeColorWithColor(ref, [UIColor colorWithWhite:1.0 alpha:0.6].CGColor);
      CGContextSetBlendMode(ref, kCGBlendModeOverlay);
    
      CGContextMoveToPoint(ref, CGRectGetMinX(contentRect), CGRectGetMinY(contentRect)+0.5);
      CGContextAddLineToPoint(ref, CGRectGetMaxX(contentRect),   CGRectGetMinY(contentRect)+0.5);
      CGContextStrokePath(ref);
     }
    

    See this blog: http://damir.me/rounded-uiview-with-shadow-the-right-way

    0 讨论(0)
  • 2020-12-07 08:47

    Adding a shadowPath should give you a huge performance boost. The following example assumes you only want the shadow on the sides of your view

    CGPathRef path = [UIBezierPath bezierPathWithRect:view.bounds].CGPath;
    [view.layer setShadowPath:path];
    

    EDIT: On default a CALayer draws a shadow during animations, the following code allows you to cache the shadow as a bitmap and reuse it instead of redrawing it:

    self.view.layer.shouldRasterize = YES;
    // Don't forget the rasterization scale
    // I spent days trying to figure out why retina display assets weren't working as expected
    self.view.layer.rasterizationScale = [UIScreen mainScreen].scale;
    
    0 讨论(0)
提交回复
热议问题