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( ...
随机推荐
- iOS 微信消息拦截插件系列教程-(总目录)
微信iOS消息拦截插件教程 标签: 越狱开发 背景介绍 本教程所有内容免费 本教程来源于一次知识分享,如果有需要了解更多的 请联系QQ:480071411 iOS逆向高级开发群:375024882 1 ...
- 通用JSONHelp 的通用的封装
1. 最近项目已经上线了 ,闲暇了几天 想将JSON 的序列化 以及反序列化进行重新的封装一下本人定义为JSONHelp,虽然Microsoft 已经做的很好了.但是我想封装一套为自己开发的项目使用 ...
- Spark Standalone Mode Configuration
For currently popular distributed framework Spark, here is the intro and step to configure the spark ...
- rang enumerate
叨逼叨: 小知识点 rang enumerate # 1. 请输出1-10# 2.7: 立即生成所有数字# range(1,11) # 生成 1,23,,4,56.10# 3.x: 不会立即生成,只有 ...
- 添加zabbix自动发现(监控多tomcat实例)
说明 何为自动发现?首先我们监控多tomcat实例,如果一个个实例地添加或许可以完成当前需求.但是日后随着实例的增多,再手动一个个去添加就十分不方便了.这时候需要自动发现这个功能,来帮助我们自动添加监 ...
- Android handler 可能会造成内存泄露
Android handler 可能会造成内存泄露 Android Studio 使用 Handler 时: private Handler handler = new Handler(){ @Ove ...
- 第一课 1) 控制div属性 总结
点击按钮变换属性: <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...
- [信息安全] 4.一次性密码 && 身份认证三要素
[信息安全]系列博客:http://www.cnblogs.com/linianhui/category/985957.html 在信息安全领域,一般把Cryptography称为密码,而把Passw ...
- 创建 Machine - 每天5分钟玩转 Docker 容器技术(46)
对于 Docker Machine 来说,术语 Machine 就是运行 docker daemon 的主机.“创建 Machine” 指的就是在 host 上安装和部署 docker.先执行 doc ...
- ural 1989 subplindromes
https://vjudge.net/problem/URAL-1989 题意: 先给出一个字符串,对于这个字符串,有两种操作,一种是询问从下标x到y的串是不是回文串,另一种是将下标为pos的字符改为 ...