您的位置:首页 > 移动开发 > IOS开发

IOS设计: 图形性能分析

2016-04-23 19:47 393 查看
注:本文只是提取了其中的主要部分进行了翻译,文章出现在较早,现在可能有不同的地方,具体操作请依据新版本的Xcode进行使用,原文还有其他的参考,还是建议大家多看原文  PS:本文第一次翻译,英语较渣,如有翻译不合适的地方请大家留言指出。

显示的内幕

IOS图形显示的层次结构


UIKit是负责IOS的图层管理的接口。他有很多类组成,各个类能够响应具体的UIControl的事件,例如UIButton和UILable。UIKit是CA的上层,CA是用于处理平滑转换的框架。

OpenGL ES是开源的用于处理图形的框架,包括游戏动画和UIKit和CA,CG就是我们常说的Quartz,基于CPU的。

硬件加速就是我们常说的GPU渲染图形,例如用到OPenGL和基于它的CA和UIkit。大多数的动画要想显示的很好都应当使用GPU进行加速。

离屏渲染指的在GPU进行屏幕渲染前是用CPU来处理bitmap图形。以下几种情况会自动进行离屏渲染:

CoreGraphic类(以CG开头的类)
drawRect方法(即使是空实现即在你的代码中显示的声明了)
CALayer的shouldRasterize设为YES
CALayer使用setMaskToBounds或设置阴影setShadow*
任何字体的显示,即使是CoreText
透明组 UIGroupOpacity
我们可以使用Instruments来进行查看离屏渲染的部分
1.把设备连入MAC
2.Xcode中打开Instruments


3.选择IOS>Graphics>CA


4.打开详细面板


5.选择要查看的设备
6.勾选Color OffScreen-Render Yellow 按钮
7.打开设备即可看到离屏渲染的部分,用黄色标识


补充:因为MAC的CPU远高于IOS设备的CPU(这是补充部分。。。),如果要是进行性能测试的话最好用真机显示,如果只是想看本例中的形式,IOS模拟器也可以
用UIButton来举例
使用预渲染
对于保存在磁盘上的图像,当我们用一个UIImage时它默认是GPU进行渲染的,这种事低消耗的而且是利用GPU来伸缩或铺像素进行显示。

CALyer
当我们设置圆角矩形的时候会进行离屏渲染,此时不得不禁用动画。总的来说,如果需要动画,那么它是不可行的

DrawRect
它依赖于CG自定义动画,缺点在于事件处理的时候,一个点击会进行两次的setNeedsDisaplay的调用,增加CPU和内存的负担,特别是多个Button的时候
混合的方法(本文支持和建议的)
如果我们需要灵活的用代码来进行绘画,那么可行的方案是制造一个可伸缩的可重用的bitmap图像给所有的实例
首先常见一个子类集成UIButton,同时加入静态变量
// In CBHybrid.m
#import "CBHybrid.h"

@implementation CBHybrid

// Resizable background image for normal state
static UIImage *gBackgroundImage;

// Resizable background image for highlighted state
static UIImage *gBackgroundImageHighlighted;

// Background image border radius and height
static int borderRadius = 5;
static int height = 37;


下一步就是画图用Bezier曲线,目标是产生可重用的图像给静态变量
</pre></div><div style="text-align:left"><pre name="code" class="objc">- (UIImage *)drawBackgroundImageHighlighted:(BOOL)highlighted {
// Drawing code goes here
}
设置图像的宽度(最佳操作设置1pt的可伸缩区域+2*radius,button默认进行背景图像拉伸,设置少了可以体验性能)和高度37pt,接下来bitmap Context
UIGraphicsBeginImageContextWithOptions(CGSizeMake(width, height), NO, 0.0);
CGContextRef context = UIGraphicsGetCurrentContext();
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

参数NO指的是不透明,0.0指的是缩放比例和设备相同(不同的IOS的缩放比例是不同的视网膜屏的要高于非视网膜屏的,具体比例数据请自行度娘),接下来是用Bezier曲线进行绘图,要考虑到Highlighted的情况
// Gradient Declarations
// NSArray *gradientColors = ...

// Draw rounded rectangle bezier path
UIBezierPath *roundedRectanglePath = [UIBezierPath bezierPathWithRoundedRect: CGRectMake(0, 0, width, height) cornerRadius: borderRadius];

// Use the bezier as a clipping path
[roundedRectanglePath addClip];

// Use one of the two gradients depending on the state of the button
CGGradientRef background = highlighted? highlightedGradient : gradient;

// Draw gradient within the path
CGContextDrawLinearGradient(context, background, CGPointMake(140, 0), CGPointMake(140, height-1), 0);

// Draw border
// [borderColor setStroke...

// Draw Inner Glow
// UIBezierPath *innerGlowRect...
输出图像和进行清理工作

现在就有了实现背景图片的方法,下面是进行封装形成一个通用的初始化方法
- (void)setupBackgrounds {

// Generate background images if necessary
if (!gBackgroundImage && !gBackgroundImageHighlighted) {
gBackgroundImage = [[self drawBackgroundImageHighlighted:NO] resizableImageWithCapInsets:UIEdgeInsetsMake(borderRadius, borderRadius, borderRadius, borderRadius) resizingMode:UIImageResizingModeStretch];
gBackgroundImageHighlighted = [[self drawBackgroundImageHighlighted:YES] resizableImageWithCapInsets:UIEdgeInsetsMake(borderRadius, borderRadius, borderRadius, borderRadius) resizingMode:UIImageResizingModeStretch];
}

// Set background for the button instance
[self setBackgroundImage:gBackgroundImage forState:UIControlStateNormal];
[self setBackgroundImage:gBackgroundImageHighlighted forState:UIControlStateHighlighted];
}
返回button类型和如果是用代码创建的button需要实现initWithCoder(或initWithFrame)

测试和运行:将butoon改成本文的子类并将内容改成CGContext-Gradient图像



代码:https://github.com/kaishin/custom-UIButton/blob/master/Custom%20UIButtons/CBHybrid.m

原文链接:https://robots.thoughtbot.com/designing-for-ios-graphics-performance
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息