iOS高效增加圆角,给layer同一时候增加mask和shadow

个别独立给layer设置圆角和影子都以相比轻便的,在此地就不多说了。而一旦同时给layer增加mask和影子就能非常,因为设置mask后阴影也会被切掉。而大家要求的是他们共处,为了化解这几个标题本身在英特网找到了以下措施:IOS
view的圆角和阴影并存iOS how-to mask and shadow an
image怎么样让阴影和圆角同时完结

1.怎么样是离屏渲染

gpu(图形学管理器)显示器渲染有三种情势:

On-Screen Rendering
 当前荧屏渲染,指的是GPU的渲染操作是在现阶段用来突显的荧屏缓冲区中举行。

Off-Screen Rendering
 离屏渲染,指的是GPU在当下荧屏缓冲区以外新开垦二个缓冲区举办渲染操作。

上面包车型地铁图景或操作会吸引离屏渲染:

但是上边的办法可能就是太费事,要么便是不吻合大家的须求,上面介绍下小编付诸的一种格局:自定义view,修改其layerClass为CAShapeLayer,
代码如下:

2.为何离屏渲染的代价异常的大

离屏渲染需求在此时此刻显示屏缓冲区以外成立叁个新的缓冲区。

全体离屏渲染的进度中,需求张开屡屡上下文切换。

第一从将上下文碰到从近来显示屏切换成离屏实行离屏渲染。渲染截止将来,要求将离屏渲染缓冲区的结果显示到荧屏上。然后再将上下文境况从离屏切换来当前显示器。但是,上下文切换的代价是非常的大的。

安装透明(阿尔法)属性
为图层设置遮罩(layer.mask)
将图层的layer.masksToBounds / view.clipsToBounds属性设置为true
将图层layer.allowsGroupOpacity属性设置为YES和layer.opacity小于1.0
为图层设置阴影(layer.shadow *)。
为图层设置layer.shouldRasterize=true
具有layer.cornerRadius,layer.edgeAntialiasingMask,layer.allowsEdgeAntialiasing的图层
文件(任何类型,满含UILabel,CATextLayer,Core
Text等)使用CGContext在drawRect
:方法中绘制大多数情状下会促成离屏渲染,乃至独有是贰个空的落实
iOS 9.0 此前UIimageView跟UIButton设置圆角都会触发离屏渲染。
iOS 9.0
之后UIButton设置圆角会触发离屏渲染,而UIImageView里png图片设置圆角不会触发离屏渲染了,借使设置任何阴影效果之类的照旧会触发离屏渲染的。

// .h#import <UIKit/UIKit.h>@interface ShapeView : UIView@end// .m@implementation ShapeView+ layerClass { return [CAShapeLayer class];}- (instancetype)init{ self = [super init]; if  { ((CAShapeLayer *)self.layer).fillColor = [UIColor colorWithRed:0 green:1 blue:1 alpha:1.0].CGColor; } return self;}-layoutSubviews{ [super layoutSubviews]; UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds byRoundingCorners:UIRectCornerTopLeft | UIRectCornerBottomLeft cornerRadii:CGSizeMake]; ((CAShapeLayer *)self.layer).path = maskPath.CGPath; }- setBackgroundColor:(UIColor *)backgroundColor { ((CAShapeLayer *)self.layer).fillColor = backgroundColor.CGColor;}@end

3.离屏渲染的触及情势

在安装了以下属性未来,都会触发离屏渲染:

shouldRasterize(光栅化)//光栅化和离屏渲染的主题素材再商讨

masks(遮罩)

ps:设置圆角语句小编并不会触发离屏渲染。view.layer.cornerRadius = 5;

不过设置圆角属性只在有个别一定情景下有效,即视图的背景和边际。纵然要给UILabel设置圆角属性,就必要两行代码:

label.layer.cornerRadius = 5;

label.layer.masksToBounds = true; 

而第二行代码设置masksToBounds就能触发离屏渲染。

shadows(阴影)

edge antialiasing(抗锯齿)

group opacity(不透明)

常用的多少个优化

接下来可以Infiniti制的设置阴影了,並且不受mask的影响:

4.匠心独运的离屏渲染

遵照事先的布道,假设将不在GPU的近期荧屏缓冲区中开展的渲染都称呼离屏渲染,那么就还或者有另一种极度的“离屏渲染”方式:CPU渲染。

只要我们重写了drawRect方法,何况利用别的Core
Graphics的技能拓宽了绘图操作,就涉嫌到了CPU渲染。整个渲染进程由CPU在App内联合地做到,渲染获得的bitmap最终再交由GPU用于显示。

1、圆角优化

 ShapeView* shapeView = [[ShapeView alloc] init]; shapeView.backgroundColor = [UIColor grayColor]; shapeView.layer.shadowColor = [UIColor redColor].CGColor; shapeView.layer.shadowRadius = 5.f; shapeView.layer.shadowOffset = CGSizeMake; shapeView.layer.shadowOpacity = 1.f; shapeView.frame = CGRectMake(100, 200, 500, 100); [self.view addSubview:shapeView];

5.显示器渲染的选择

明天有二种荧屏渲染方式:当前显示器渲染格局、离屏渲染、CPU渲染。

尽恐怕选取当前显示屏渲染

鉴于离屏渲染、CPU渲染可能带来的个性难点,一般景观下,大家要硬着头皮采纳当前显示屏渲染。

离屏渲染 VS CPU渲染

鉴于GPU的浮点运算技艺比CPU强,CPU渲染的频率或然不及离屏渲染;但假设唯有是贯彻一个大致的成效,直接动用CPU渲染的频率又只怕比离屏渲染好,毕竟离屏渲染要提到到缓冲区创建和上下文切换等耗时操作。

在应用软件开荒中,圆角图形依然平日出现的。借使四个界面中独有一点点圆角图片或者对质量未有相当的大的影响,可是当圆角图片比非常多的时候就能够APP质量发生显明的震慑。
笔者们设置圆角一般通过如下格局:

举个例子再想设置border,能够用上面方法:

6.由此设置CALayer的mask

设置view.layer.mask同样会掀起离屏渲染难题,进而减少fps(每秒传输帧数量)。

有两种转移遮罩的章程:

// 通过图形生成遮罩

UIImage*maskImage = [UIImageimageNamed:@”someimg”];

CALayer*mask = [CALayernew];mask.frame =CGRectMake(0,0,
maskImage.size.width, maskImage.size.height);

mask.contents = (__bridgeid_Nullable)(maskImage.CGImage);

view.layer.mask = mask;

//通过贝塞尔曲线生成

CAShapeLayer*mask = [CAShapeLayernew];

mask.path =
[UIBezierPathbezierPathWithOvalInRect:view.bounds].CGPath;

view.layer.mask = mask;

imageView.layer.cornerRadius=CGFloat(10);
imageView.layer.masksToBounds=YES;
 // 这个地方的path和自定义view的layer的path相同 UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:shapeView.bounds byRoundingCorners:UIRectCornerTopLeft | UIRectCornerBottomLeft cornerRadii:CGSizeMake]; CAShapeLayer* borderLayer = [CAShapeLayer layer]; borderLayer.path = maskPath.CGPath; borderLayer.fillColor = [UIColor clearColor].CGColor; borderLayer.strokeColor = [UIColor greenColor].CGColor; borderLayer.frame = shapeView.bounds; [shapeView.layer addSublayer:borderLayer];

7.利用Core Graphics手动画出圆角

本条方法是在CPU中另行绘制一份圆角视图以落成圆角作用,那样做会追加CPU的付出,。不过这种办法不会触发离屏渲染,不会回退fps。

代码笔者就不写了,因为自己不会用那几个怎么down 。。。

参考:制图圆角的八种办法

优化方案1:使用贝塞尔曲线UIBezierPath和Core Graphics框架画出二个圆角

想要的功力就出去了,阴影、圆角、边框俱全:

8.混合图层

在要增多圆角的视图上增加三个部分透明的视图,只对圆角举行屏蔽。这种办法不会挑起离屏渲染,也没有须求占用CPU财富,但是使用场景有限。

参考:

iOS
高效增添圆角作用实战讲解

小心别让圆角成了你列表的帧数刺客

离屏渲染学习

UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(100, 100, 100, 100)]; 
imageView.image = [UIImage imageNamed:@"myImg"]; 
//开始对imageView进行画图 
UIGraphicsBeginImageContextWithOptions(imageView.bounds.size, NO, 1.0); 
//使用贝塞尔曲线画出一个圆形图 
[[UIBezierPath bezierPathWithRoundedRect:imageView.bounds cornerRadius:imageView.frame.size.width/2.0] addClip];
[imageView drawRect:imageView.bounds];
imageView.image = UIGraphicsGetImageFromCurrentImageContext(); 
//结束画图 
UIGraphicsEndImageContext();
[self.view addSubview:imageView];

图片 1

优化方案2:使用CAShapeLayer和UIBezierPath设置圆角

若果你有更加好的艺术,应接留言调换。

UIImageView *imageView=[[UIImageView alloc]initWithFrame:CGRectMake(100,100,100,100)];
imageView.image=[UIImage imageNamed:@"myImg"];
UIBezierPath *maskPath=[UIBezierPath bezierPathWithRoundedRect:imageView.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:imageView.bounds.size];
CAShapeLayer *maskLayer=[[CAShapeLayer alloc]init];
//设置大小
maskLayer.frame=imageView.bounds;
//设置图形样子
maskLayer.path=maskPath.CGPath;
imageView.layer.mask=maskLayer;
[self.view addSubview:imageView];


对于方案2的解释:

使用CAShapeLayer(属于CoreAnimation)与贝塞尔曲线可以实现不在view的drawRect(继承于CoreGraphics走的是CPU,消耗的性能较大)方法中画出一些想要的图形
CAShapeLayer动画渲染直接提交到手机的GPU当中,相较于view的drawRect方法使用CPU渲染而言,其效率极高,能大大优化内存使用情况。
总的来说就是用CAShapeLayer的内存消耗少,渲染速度快,建议使用优化方案2。

2、shadow优化

对于shadow,如果图层是个简单的几何图形或者圆角图形,我们可以通过设置shadowPath来优化性能,能大幅提高性能。示例如下:

imageView.layer.shadowColor=[UIColor grayColor].CGColor;
imageView.layer.shadowOpacity=1.0;
imageView.layer.shadowRadius=2.0;
UIBezierPath *path=[UIBezierPath bezierPathWithRect:imageView.bounds];
imageView.layer.shadowPath=path.CGPath;
我们还可以通过设置shouldRasterize属性值为YES来强制开启离屏渲染。其实就是光栅化(Rasterization)。既然离屏渲染这么不好,为什么我们还要强制开启呢?当一个图像混合了多个图层,每次移动时,每一帧都要重新合成这些图层,十分消耗性能。当我们开启光栅化后,会在首次渲染的时候产生一个位图缓存,当再次使用时候就会复用这个缓存。但是如果图层发生改变的时候就会重新产生位图缓存。所以这个功能一般不能用于UITableViewCell中,cell的复用反而降低了性能。最好用于图层较多的静态内容的图形。而且产生的位图缓存的大小是有限制的,一般是2.5个屏幕尺寸。在100ms之内不使用这个缓存,缓存也会被删除。所以我们要根据使用场景而定。

3、其他的一些优化建议

当我们需要圆角效果时,可以使用一张中间透明图片蒙上去
使用ShadowPath指定layer阴影效果路径
使用异步进行layer渲染(Facebook开源的异步绘制框架AsyncDisplayKit)
设置layer的opaque值为YES,减少复杂图层合成(如果opaque设置NO,那么Alpha应该小于1)
尽量使用不包含透明(alpha)通道的图片资源
尽量设置layer的大小值为整形值
直接让美工把图片切成圆角进行显示,这是效率最高的一种方案
很多情况下用户上传图片进行显示,可以让服务端处理圆角
使用代码手动生成圆角Image设置到要显示的View上,利用UIBezierPath(CoreGraphics框架)画出来圆角图片
3、其它

1) 减少视图的数目:
我们在cell上添加系统控件的时候,实际上系统都会调用底层的接口进行绘制,大量添加控件时,会消耗很大的资源并且也会影响渲染的性能。当使用默认的UITableViewCell并且在它的ContentView上面添加控件时会相当消耗性能。所以目前最佳的方法还是继承UITableViewCell,并重写drawRect方法,并且这里的绘制过程可以通过多线程异步绘制。
2)减少多余的绘制操作:
在实现drawRect方法的时候,它的参数rect就是我们需要绘制的区域,在rect范围之外的区域我们不需要进行绘制,否则会消耗相当大的资源。
3)不要给cell动态添加subView:
在初始化cell的时候就将所有需要展示的添加完毕,然后根据需要来设置hide属性显示和隐藏。
4)滑动时按需加载对应的内容:
滑动很快时,只加载目标范围内的cell,这样按需加载(配合SDWebImage),极大提高流畅度,但是这样在滑动过程中就会暂时显示空白

作者:Tamp__
链接:http://www.jianshu.com/p/13f097d9a1d4
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

参考: CALayer的autolayout

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*
*
Website