当前位置: 首页 > 科技观察

iOS和常见的离屏渲染SayGoodbye!

时间:2023-03-14 08:02:21 科技观察

手机应用优化主要看FPS(页面流畅度)性能、内存占用等方面。离屏渲染也是一个老生常谈的问题。本文重点介绍导致离屏渲染的常见因素及解决方法。那么为什么离屏渲染会导致性能问题呢?在OpenGL中,GPU屏幕渲染有两种方式:On-ScreenRendering(当前屏幕渲染)和Off-ScreenRendering(离屏渲染)。当前屏幕渲染不需要额外创建新的Cache,不需要开启新的context,比离屏渲染有更好的性能。但是由于当前屏幕渲染的限制(只有自身的上下文,有限的屏幕缓存等),在某些情况下当前屏幕渲染无法通过渲染解决,就采用离屏渲染。离屏渲染的整个过程需要切换上下文环境,先从当前屏幕切换到离屏,结束后再将上下文环境切换回来。这就是它消耗性能的原因。造成离屏渲染的因素有cornerRadius(设置圆角)、shadows(阴影)、masks(遮罩)、edgeantialiasing(抗锯齿)、groupopacity(不透明度)、shouldRasterize(光栅化)等。至于检测off-屏幕渲染工具Instruments的CoreAnimation就不多说了。本文主要介绍设置圆角和阴影的方案。设置圆角的一般做法://只需要设置图层layer的两个属性//设置圆角imageView.layer.cornerRadius=imageView.frame.size.width/2;//剪掉多余的部分imageView.layer.masksToBounds=YES;这里有两种避免离屏渲染的解决方案1.在view的顶层添加一个sublayer来覆盖view和它的子view,并设置layer的图片刚好覆盖需要的圆角,以及view的颜色图片只是视图的父视图的背景颜色,以达到预期的效果。github地址/**设置四角圆角@paramradius圆角半径@paramcolor圆角背景色*/-(void)xw_roundedCornerWithRadius:(CGFloat)radiuscornerColor:(UIColor*)color;/**设置普通圆角@paramradius圆角半径@paramcolor圆角背景颜色@paramcorners圆角位置*/-(void)xw_roundedCornerWithRadius:(CGFloat)radiuscornerColor:(UIColor*)colorcorners:(UIRectCorner)corners;/**设置有边角@paramcornerRadiiCorner半径cornerRadii@paramcolor圆角背景颜色@paramcorners圆角位置@paramborderColor边框颜色@paramborderWidth边框线宽*/-(void)xw_roundedCornerWithCornerRadii:(CGSize)cornerRadiicornerColor:(UIColor*)colorcorners:(UIRectCorner)cornersborderColor:(UIColor*)borderColorborderWidth:(CGFloat)borderWidth;下载该类后,直接拖入项目即可使用。调用起来很方便,但是当你使用的时候,你会发现这三个API都需要传递一个参数cornerColor(父视图的背景色),所以也造成了这个函数的局限性,即如果父视图的颜色不是纯色,这个方法暂时不适用。同样,如果父视图的颜色发生变化,实现它的代码也不是那么优雅,如下图,有点尴尬,这里引出第二种方案。拐角颜色与背景颜色不匹配2.通过修改layer.mask,先通过贝塞尔曲线创建一个基于矢量的路径,传给CAShapeLayer进行渲染。路径闭合,然后将绘制的Shape赋给layer.mask,Mask范围外的Layer将不显示,达到圆角效果。代码实现很简单,如下:UIButton*btn=[[UIButtonalloc]initWithFrame:CGRectMake(130,330,100,100)];[btnsetBackgroundColor:[UIColorcolorWithRed:(226.0/255.0)green:(113.0/255.0)blue:(19.0/255.0)alpha1]];[backgroundImageViewaddSubview:btn];//绘制曲线路径;maskLayer.frame=btn.bounds;//设置图形的形状maskLayer.path=maskPath.CGPath;btn.layer.mask=maskLayer;效果图:个人认为第二种方案更简单,功能扩展性更强。设置阴影例程实践://阴影的颜色self.imageView.layer.shadowColor=[UIColorblackColor].CGColor;//阴影的透明度self.imageView.layer.shadowOpacity=0.8f;//圆角阴影的self.imageView.layer.shadowRadius=4;//阴影偏移self.imageView.layer.shadowOffset=CGSizeMake(0,0);优化方案:避免直接修改shadowOffset,通过调用setShadowPath为view的Layer提供CGPath,为CoreAnimation提供渲染View的shape会减少离屏渲染计算[self.imageView.layersetShadowPath:[[UIBezierPathbezierPathWithRect:myView.bounds]CGPath]];补充:当使用阴影的view的shape发生变化时,即shadowPath不会跟随CALayer的bounds属性变化,所以当图层的bounds发生变化后,shadowPath需要手动更新以适应新界限