在iOS上最快的阴影方式?

时间:2021-04-14 01:35:02

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

QuartzCore .layer.shadow吸收了性能。它们似乎需要在每次发生变化时重新渲染,导致一切都滞后。

Coregraphics gradient (for 1 way shadows) - doesn't look right. if your gradient goes from 0.3 alpha to 0, it has some odd effect where you can 'see' it stop. It just doesn't look nice, or natural. Maybe it isn't dithered, but I'm sure I heard core graphics gradients are. It's odd, I don't know.

Coregraphics渐变(用于单向阴影) - 看起来不正确。如果你的渐变从0.3 alpha变为0,它会有一些奇怪的效果,你可以“看到”它停止。它看起来不漂亮或自然。也许它没有抖动,但我确信我听说过核心图形渐变。这很奇怪,我不知道。

Coregraphics shadow - take a while to render as you set them, but otherwise great performance. It's just that second you're waiting for a view to appear because it has to render it's shadow first, that's the problem.

Coregraphics阴影 - 在设置它们时需要一段时间来渲染,但其他方面性能很好。只是第二个你正在等待视图出现,因为它必须首先渲染它的阴影,这就是问题所在。

So I must be missing something. Is there another method which looks right, and is speedy both in rendering time and in performance?

所以我一定错过了什么。还有另一种看起来正确的方法,并且在渲染时间和性能方面都很快吗?

2 个解决方案

#1


101  

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

添加shadowPath应该会为您带来巨大的性能提升。以下示例假设您只希望视图两侧有阴影

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:

编辑:默认情况下,CALayer在动画期间绘制阴影,以下代码允许您将阴影缓存为位图并重复使用而不是重绘它:

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;

#2


9  

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!

这会产生巨大的性能影响,尤其是阴影效果。将这样的视图放在UITableView中(或事实上任何移动的东西)将创建一个Android-ish滚动体验,你不需要它。如果您需要设置动画或移动视图,请避免以任何方式创建圆角或阴影!

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.

满足Core Graphics我已经创建了一个简单的UIView子类,向您展示如何以稍微不同的方式实现相同的结果。它使用Core Graphics绘制视图,与上面的代码形成对比,它不会影响性能。

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

请参阅此博客:http://damir.me/rounded-uiview-with-shadow-the-right-way

#1


101  

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

添加shadowPath应该会为您带来巨大的性能提升。以下示例假设您只希望视图两侧有阴影

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:

编辑:默认情况下,CALayer在动画期间绘制阴影,以下代码允许您将阴影缓存为位图并重复使用而不是重绘它:

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;

#2


9  

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!

这会产生巨大的性能影响,尤其是阴影效果。将这样的视图放在UITableView中(或事实上任何移动的东西)将创建一个Android-ish滚动体验,你不需要它。如果您需要设置动画或移动视图,请避免以任何方式创建圆角或阴影!

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.

满足Core Graphics我已经创建了一个简单的UIView子类,向您展示如何以稍微不同的方式实现相同的结果。它使用Core Graphics绘制视图,与上面的代码形成对比,它不会影响性能。

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

请参阅此博客:http://damir.me/rounded-uiview-with-shadow-the-right-way