iOS的阴影绘制及性能优化
今天来讲讲iOS开发过程中的阴影绘制及其潜在的绘图性能问题。虽然在开发过程中,我们使用阴影功能的机会不是很多,但是如果用了,有可能引起如卡顿等性能问题,所以,还是有必要来探究一下阴影的绘制过程,及如何提高阴影的绘制性能。
阴影绘制
阴影可以通过设置layer层的shadowXXX属性,就可以很方便的为UIView添加阴影效果,但是不同的设置方式可能产生性能方面的问题,下面介绍一下不同方式对性能的影响。
方式一
通过设置下面的4个属性,就可以添加阴影,这种方式可能产生性能问题,因为绘制阴影而不指定阴影路径,在绘制阴影过程中,就会产生大量的离屏渲染(Offscreen-Rendered),非常消耗性能,进而造成动画卡顿的问题。
离屏渲染
造成离屏渲染的原因很多,比如:遮罩、阴影、抗锯齿等等,而阴影造成离屏渲染的原因是:iOS会先绘制目标的阴影,然后绘制目标的本身,在没有指定阴影的绘制路径时,iOS视图在每次绘制前都会递归的精确计算每个子层阴影的路径,这会非常消耗性能,也是导致卡顿的根源。
所以,如果绘制的阴影不是很多的情况下,该方法不会消耗大量性能,绘制就会比较简单,代码量也少。
// 设置阴影颜色
self.imageView1.layer.shadowColor = [UIColor orangeColor].CGColor;
// 设置阴影的偏移量,默认是(0, -3)
self.imageView1.layer.shadowOffset = CGSizeMake(4, 4);
// 设置阴影不透明度,默认是0
self.imageView1.layer.shadowOpacity = 0.8;
// 设置阴影的半径,默认是3
self.imageView1.layer.shadowRadius = 4;

方式二
为了减少因为没有设置shadowPath造成绘制阴影时大量重复绘制的问题,我们可以指定阴影的绘制路径,这样在绘制阴影时,就可以在多个layer层共享同一个路径的阴影,以此来提高性能,下面是苹果官方文档是解释:
/* When non-null this path defines the outline used to construct the
* layer's shadow instead of using the layer's composited alpha
* channel. The path is rendered using the non-zero winding rule.
* Specifying the path explicitly using this property will usually
* improve rendering performance, as will sharing the same path
* reference across multiple layers. Upon assignment the path is copied.
* Defaults to null. Animatable. */
@property(nullable) CGPathRef shadowPath;
shadowPath的注释大意就是说如果不指定路径,就会使用layer层的alpha通道的混合,而如果指定阴影路径,就会在多个layer层之间共享同一路径,以此来提高性能。
有关什么是layer层的混合,可以这样理解:iOS在渲染每一帧时,都会计算每一个像素的颜色,如果上层layer不透明,就只取上层layer的颜色;而如果上层layer存在透明度时(alpha通道),则需要混合每一层的颜色来计算最终的颜色。如果layer越多,计算量就越大,也就比较耗性能。所以,在开发中,要尽量减少视图的透明层。
具体代码示例,具体是功能就是绘制一个边框阴影:
_imageView.layer.shadowColor = [UIColor yellowColor].CGColor;//shadowColor阴影颜色
_imageView.layer.shadowOffset = CGSizeMake(0,0);//shadowOffset阴影偏移,默认(0, -3),这个跟shadowRadius配合使用
_imageView.layer.shadowOpacity = 1;//阴影透明度,默认0
_imageView.layer.shadowRadius = 3;//阴影半径,默认3
//路径阴影
UIBezierPath *path = [UIBezierPath bezierPath];
float width = _imageView.bounds.size.width;
float height = _imageView.bounds.size.height;
float x = _imageView.bounds.origin.x;
float y = _imageView.bounds.origin.y;
float addWH = 10;
CGPoint topLeft = _imageView.bounds.origin;
CGPoint topMiddle = CGPointMake(x+(width/2),y-addWH);
CGPoint topRight = CGPointMake(x+width,y);
CGPoint rightMiddle = CGPointMake(x+width+addWH,y+(height/2));
CGPoint bottomRight = CGPointMake(x+width,y+height);
CGPoint bottomMiddle = CGPointMake(x+(width/2),y+height+addWH);
CGPoint bottomLeft = CGPointMake(x,y+height);
CGPoint leftMiddle = CGPointMake(x-addWH,y+(height/2));
[path moveToPoint:topLeft];
//添加四个二元曲线
[path addQuadCurveToPoint:topRight
controlPoint:topMiddle];
[path addQuadCurveToPoint:bottomRight
controlPoint:rightMiddle];
[path addQuadCurveToPoint:bottomLeft
controlPoint:bottomMiddle];
[path addQuadCurveToPoint:topLeft
controlPoint:leftMiddle];
//设置阴影路径
_imageView.layer.shadowPath = path.CGPath;

综上,以后开发过程中,如果用到阴影效果,在视图图层不是很多,阴影视图计算量少的情况下,可以直接设置阴影,但是如果图层较多,阴影的计算量较大,则要考虑使用path的方式。(本文主要参考互联网,版本归原作者所有)
参考资料
iOS的阴影绘制及性能优化的更多相关文章
- iOS性能优化-异步绘制
参考地址:https://blog.ibireme.com/2015/11/12/smooth_user_interfaces_for_ios/ 很久以前就看过这篇文章,但是也只是看过就过了,没有去整 ...
- iOS程序性能优化
iOS程序性能优化 一.初级 使用ARC进行内存管理 在iOS5发布的ARC,它解决了最常见的内存泄露问题.但是值得注意的是,ARC并不能避免所有的内存泄露.使用ARC之后,工程中可能还会有内存泄露, ...
- iOS 程序性能优化
前言 转载自:http://www.samirchen.com/ios-performance-optimization/ 程序性能优化不应该是一件放在功能完成之后的事,对性能的概念应该从我们一开始写 ...
- [iOS Animation]-CALayer 性能优化
性能优化 代码应该运行的尽量快,而不是更快 - 理查德 在第一和第二部分,我们了解了Core Animation提供的关于绘制和动画的一些特性.Core Animation功能和性能都非常强大,但如果 ...
- iOS进阶之页面性能优化
转载:http://www.jianshu.com/p/1b5cbf155b31 前言 在软件开发领域里经常能听到这样一句话,"过早的优化是万恶之源",不要过早优化或者过度优化.我 ...
- iOS 性能优化总结
卡顿产生的原因 在 VSync信号到来后,系统图形服务会通过 CADisplayLink等机制通知 App,App主线程开始在 CPU中计算显示内容,比如视图的创建.布局计算.图片解码.文本绘制等.随 ...
- iOS页面性能优化
前言 在软件开发领域里经常能听到这样一句话,“过早的优化是万恶之源”,不要过早优化或者过度优化.我认为在编码过程中时刻注意性能影响是有必要的,但凡事都有个度,不能为了性能耽误了开发进度.在时间紧急的情 ...
- iOS开发系列之性能优化(上)
本篇主要记录一下我对界面优化上的一些探索.关于时间优化的探索将会在中篇里进行介绍.下篇将主要介绍一些耗电优化.安装包瘦身的探索. ### 1.卡顿原理 要了解卡顿原理,需要对帧缓冲区.垂直同步.CPU ...
- iOS性能优化-数组、字典便利时间复杂
上图是几种时间复杂度的关系,性能优化一定程度上是为了降低程序执行效率减低时间复杂度. 如下是几种时间复杂度的实例: O(1) return array[index] == value; 复制代码 O( ...
随机推荐
- (转载)提高系统OOP抽象以应对复杂的需求
提高系统OOP抽象以应对复杂的需求, 转自:http://www.nowamagic.net/librarys/veda/detail/1373 有人问我如何构建一个比较好的类阶层次,如何使用面向对象 ...
- God 1.1.1 多线程之内存可见性
共享变量在线程间的可见性 synchronize实现可见性 volatile实现可见性 指令重排序 as-if-serial语义 volatile使用注意事项 synchronized和volatil ...
- 关于Lumen / Laravel .env 文件中的环境变量是如何生效的
.env 文件包含默认环境变量,我们还可自定义其他任何有效的变量,并可通过 调用 env() 或 $_SERVER 或 $_ENV 来获取该变量.那么env()是如何加载到这些变量的呢?在Lume ...
- fedora下一些问题的解决方案汇总
解决fedora下一些使用问题 一 解决fedora下无法使用Fn+功能键来调整亮度的问题 在fedora下,背光的配置参数在/sys/class/backlight文件夹下,根据不同的显卡,有不同的 ...
- webstrom一键上传github及使用
对于webstrom是我参加it修真园时就推荐使用的,其他编辑器我也没什么使用过.读大学的时候还是比较喜欢 Notepad++. 现在说一下webstrom主要的关键点吧! 一.实现一键上传githu ...
- Vue2.0 生产环境部署
简要:继上次搭建vue环境后,开始着手vue的学习;为此向大家分享从开发环境部署到生产环境(线上)中遇到的问题和解决办法,希望能够跟各位VUE大神学习探索,如果有不对或者好的建议告知下:*~*! 一. ...
- docker - 修改镜像/容器文件的在宿主机上的存储位置(转)
背景 之前在使用docker的时候,由于启动container的时候用的是默认的mount(路径为 /var/lib/docker),这个目录对应的硬盘空间有限,只有200G左右.现在随着程序运行,有 ...
- Oozie时出现org.apache.oozie.service.ServiceException: E0103: Could not load service classes, Cannot load JDBC driver class 'com.mysql.jdbc.Driver'
不多说,直接上干货! 问题详情 查看你的$OOZIE_HOME/logs 我的是/home/hadoop/app/oozie-4.1.0-cdh5.5.4/logs/oozie.log文件 [hado ...
- 常用PHP函数
md5_file() 生成md5 $zip = new \ZipArchive(); if($zip->open($savepath.$key) === TRUE){ $zip ->ext ...
- 将Asp.Net Core和corefx移植到.Net 4.0
引言 因为工作内容的原因需要兼容 XP,而 XP 最多支持到.Net Framework 4.0.因此无法享受到 .Net Core 带来的一堆很好用的库,好在无论 corefx 还是 Asp.Net ...