iOS设置shadow*带来的离屏渲染

前言


在项目中,当我们想要设置View的阴影效果时,可以通过shadow*相关方法实现,如:

1
2
3
self.layer.shadowOffset = CGSizeMake(4, -2);
self.layer.shadowOpacity = 0.5;
self.layer.shadowColor = [[UIColor blackColor] colorWithAlphaComponent:0.5].CGColor;

实现效果如下:

如上实现方式,有些情况下,你并不会发现有什么问题,但是一旦将其用在如UITableViewCellUICollectionViewCell等时,你会发现,滑动时会导致大量掉帧的情况,其主要原因为,shadow*方法的使用将导致Core Animation进行离屏渲染,为了确定这一点,可以通过Instruments工具,选择Core Animation模板,选择开启Color Offscreen-Rendered Yellow Debug选项,当我们滑动CollectionView时,其帧率如下,产生了大量掉帧的情况,且正如我们所料,使用shadow*方法的视图被标黄,既使用了离屏渲染。

帧率情况如上,可以看到丢帧率很高。

解决方案


有一种很简单的方式来解决该问题,既直接向Core Animation提供阴影形状,通过调用setShadowPath来提供一个CGPath给视图的Layer,(CGPath为任意你想生成的阴影的形状),如:

1
2
[myView.layer setShadowPath:[[UIBezierPath 
bezierPathWithRect:myView.bounds] CGPath]];

再次运行InstrumentsCore Animation模板,能够看到,基本没有掉帧,滑动很流畅,且没有使用离屏渲染。

附录


  • 当使用阴影的视图形状发生变化时,可以将阴影的设置代码放入setFramelayoutSubviews等方法里。
  • 当对视图的bounds进行动画时,默认其阴影是不会跟随进行动画的,但是可以通过如CAKeyframeAnimation来对其进行动画,因为我们已经知道了新旧两个CGPath
  • 能引发离屏渲染的情况除了设置shadow,还有很多,如layer.masklayer.shouldRasterize = YES等,当然,除了离屏渲染,还有很多影响绘图性能的问题,如BlendingLayout,等。
    详细情况可参考: http://stackoverflow.com/questions/13158796/what-triggers-offscreen-rendering-blending-and-layoutsubviews-in-ios