移动应用优化到最后主要还是看FPS(页面流畅程度)性能、内存占用等方面。离屏渲染也是老生常谈的一个问题,本文侧重点在常见导致离屏渲染的因素及解决方案。

那么为什么离屏渲染会引起性能问题?

OpenGL中,GPU屏幕渲染有两种方式: On-Screen Rendering (当前屏幕渲染)Off-Screen Rendering (离屏渲染) ,当前屏幕渲染不需要额外创建新的缓存,也不需要开启新的上下文,相对于离屏渲染性能更好。但是受当前屏幕渲染的局限因素限制(只有自身上下文、屏幕缓存有限等),当前屏幕渲染有些情况下的渲染解决不了的,就使用到离屏渲染。离屏渲染的整个过程需要切换上下文环境,先从 当前屏幕切换到离屏,等结束后,又要将上下文环境切换回来.这也是为什么会消耗性能的原因了。

离屏渲染引发因素有 cornerRadius(设置圆角)、shadows(阴影)、masks(遮罩)、edge antialiasing(抗锯齿)、group opacity(不透明)、shouldRasterize(光栅化) 等,至于检测离屏渲染的工具 Instruments的Core Animation 就不多说了。本文主要介绍 设置圆角阴影 的方案。

设置圆角

常规做法:

   //只需要设置layer层的两个属性//设置圆角imageView.layer.cornerRadius = imageView.frame.size.width / 2;//将多余的部分切掉imageView.layer.masksToBounds = YES;
复制代码

这里提供两种避免离屏渲染的方案

  • 1.视图上添加一个子layer到最上层,用于遮盖该视图及其子视图,设置layer的图片为刚好能够遮盖成所需圆角样子,并且图片颜色刚好是该视图父视图的背景颜色就达到想要的效果。 原文地址 ,该作者写的很好,封装了一个UIView的分类,3个API,分别是 设置一个四角圆角,设置一个指定位置的圆角,设置一个带边框的圆角 。 github地址
/**设置一个四角圆角@param radius 圆角半径@param color  圆角背景色*/
- (void)xw_roundedCornerWithRadius:(CGFloat)radius cornerColor:(UIColor *)color;/**设置一个普通圆角@param radius  圆角半径@param color   圆角背景色@param corners 圆角位置*/
- (void)xw_roundedCornerWithRadius:(CGFloat)radius cornerColor:(UIColor *)color corners:(UIRectCorner)corners;/**设置一个带边框的圆角@param cornerRadii 圆角半径cornerRadii@param color       圆角背景色@param corners     圆角位置@param borderColor 边框颜色@param borderWidth 边框线宽*/
- (void)xw_roundedCornerWithCornerRadii:(CGSize)cornerRadii cornerColor:(UIColor *)color corners:(UIRectCorner)corners borderColor:(UIColor *)borderColor borderWidth:(CGFloat)borderWidth;
复制代码

下载下来这个分类直接拖入工程就可以使用了,调用很方便,不过使用的时候会发现,这三个API都需要传一个参数 cornerColor (父视图的背景色),所以也造成了这个功能的局限,即 如果该父视图的颜色不是纯色,此时该方式就不适用了,同样 如果父视图的颜色会变化,那实现起来的代码也不那么优雅,如下图,有点尴尬,这里引出了第二种方案。

  • 2.通过修改layer.mask,首先通过贝塞尔曲线创建基于矢量的路径 ,传递给CAShapeLayer进行渲染。路径闭环,再把绘制出的Shape赋值给layer.mask,在Mask范围之外的Layer将不被显示从而达到圆角效果。代码实现很简单,如下:
    UIButton *btn = [[UIButton alloc]initWithFrame:CGRectMake(130, 330, 100, 100)];[btn setBackgroundColor:[UIColor colorWithRed:(226.0 / 255.0) green:(113.0 / 255.0) blue:(19.0 / 255.0) alpha:1]];[backgroundImageView addSubview:btn];//绘制曲线路径UIBezierPath *maskPath = [UIBezierPath bezierPathWithRoundedRect:btn.bounds byRoundingCorners:UIRectCornerAllCorners cornerRadii:btn.bounds.size];CAShapeLayer *maskLayer = [[CAShapeLayer alloc]init];//设置大小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来提供一个CGPath给视图的Layer,向Core Animation提供渲染的View的形状Shape,就会减少离屏渲染计算

[self.imageView.layer setShadowPath:[[UIBezierPath bezierPathWithRect:myView.bounds] CGPath]];
复制代码

补充:当使用阴影的视图形状发生变化时,即shadowPath并不会跟随CALayer的bounds属性进行变化,所以在layer的bounds产生变化以后需要手动更新shadowPath才能让其适配新的bounds。具体推荐看这篇文章

关于界面流畅如果想要深层探索可以看 YYKit作者 写的文章iOS 保持界面流畅的技巧 。该文章从屏幕显示图像的原理,到改进的方案都有详细介绍。

谢谢各位,欢迎指教!

转载于:https://juejin.im/post/5a3b12daf265da433227ba91

iOS 和常见的离屏渲染Say Goodbye!相关推荐

  1. 关于iOS离屏渲染的深入研究

    在平时的iOS面试中,我们经常会考察有关离屏渲染(Offscreen rendering)的知识点.一般来说,绝大多数人都能答出"圆角.mask.阴影会触发离屏渲染",但是也仅止于 ...

  2. iOS之从OpenGL深入探究离屏渲染及性能优化

    一.探究内容 到底什么是离屏渲染?是在GPU上面还是CPU上面执行的? 为什么要有离屏渲染?什么情况下会产生离屏渲染? 帧缓冲区是什么?当前屏幕缓冲区和屏幕外缓冲区又是什么? 切换缓冲区是什么操作?真 ...

  3. iOS 离屏渲染的研究

    GPU渲染机制: CPU 计算好显示内容提交到 GPU,GPU 渲染完成后将渲染结果放入帧缓冲区,随后视频控制器会按照 VSync 信号逐行读取帧缓冲区的数据,经过可能的数模转换传递给显示器显示. G ...

  4. 【iOS高级资深工程师面试篇】①、2022年,金九银十我为你准备了《iOS高级资深工程师面试知识总结》 UI部分3/3 -UIView绘制原理-离屏渲染

    iOS高级资深工程师面试篇系列 - 已更新3篇 UI部分1/3 -UITableView-事件传递&视图响应 UI部分2/3 -图像显示原理-UI卡顿&掉帧 UI部分3/3 -UIVi ...

  5. iOS 切圆角离屏渲染问题

    GPU屏幕渲染有两种方式: 1.On-Screen Rendering(当前屏幕渲染) 指的是GPU的渲染操作是在当前显示的屏幕缓冲区进行. 2.Off-Screen Rendering(离屏渲染) ...

  6. iOS圆角避免离屏渲染

    写在前面 代码已经整理到nxlib的 nx_circleView, nx_circleImage 中, 在列表中使用圆角时建议使用这个方式. 参考阅读 离屏渲染优化详解:实例示范+性能测试 使用 In ...

  7. ios开发之离屏渲染

    前言 在介绍离屏渲染之前,首先理解下这个概念,什么是离屏渲染,为什么会出现离屏渲染,以及如何避免离屏渲染. GPU屏幕渲染有两种方式: (1)On-Screen Rendering (当前屏幕渲染) ...

  8. 离屏渲染在车载导航中的应用

    导读 与手机导航不同,高德地图的车机版(AMAP AUTO)直接面对各大车厂和众多设备商.这些B端用户采用的硬件参数参差不齐,提出的业务需求涉及到渲染中诸多复杂技术的应用,这对渲染性能提出了极高的要求 ...

  9. OpenGLES2.0渲图步骤:绘几何图形、图片处理、离屏渲染(3)

    OpenGLES2.0是一个图形渲染(图形处理)库. OpenGL ES 2.0渲染过程为:读取顶点数据--执行顶点着色器--组装图元--光栅化图元--执行片元着色器--写入帧缓冲区--显示到屏幕上. ...

最新文章

  1. 搞懂限流算法这一篇就够了 No.154
  2. EF CodeFirst数据迁移与防数据库删除
  3. 嵌入式开发调试学习与思考
  4. 你还在使用 try-catch-finally 关闭资源?不太优雅~
  5. Linux上的Shell之FAQ
  6. 编写一个汇编语言程序,完成以下要求。从BUF单元处定义有10个带符号字数据:-1,3,24,94,62,72,55,0,-48,99,试找出他们中的最大值和平均值,并以此分别存放至该数据区的后两个单元
  7. 闲话WPF之十八(WPF中的资源 [4] )
  8. c++ regex用法实例 2
  9. robotac属于a类还是b类_工程项目分类A类、B类、C类、D类项目是指什么?注意:不是资料的A、B、C类报建资料...
  10. python人工智能学习笔记_[Python] 人工智能与自然语言处理学习笔记(1)
  11. HashMap的底层原理 cr:csdn:zhangshixi
  12. Atitit.提升电子商务安全性 在线充值功能安全方面的设计
  13. ARIMA时间序列分析
  14. 解决ConnectionAbortedError: [WinError 10053] 你的主机中的软件中止了一个已建立的连接
  15. 简约好看导航栏(HTML、CSS)
  16. Docker教程:dokcer machine的概念和安装
  17. 西威变频器avo下载调试资料_西门子变频器使用BOP-2 面板调试 G120
  18. react使用echarts地图实现中国地图大区展示
  19. Canny边缘检测非极大值抑制法在双立方插值(Bicubic)图像边缘优化
  20. charles限制网速

热门文章

  1. 运用C#在采集时进行自动验证登录[转]
  2. 探寻C++最快的读取文件的方案
  3. ubuntu自动加载硬盘分区
  4. 执行DBMS_METADATA.get_ddl报ORA-39212的解决方法
  5. Webservice 的安全
  6. 设计模式(五)学习----装饰模式
  7. mysql服务的注册,启动、停止、注销。 [delphi代码实现]
  8. HLG 数字去重和排序II【二叉排序树】
  9. struts2.0.14 web.xml,struts.xml配置
  10. 机器学习实践笔记(一)KNN