iOS绘图
在iOS中常用有三套绘图API。一个是UIKit提供的高层API,一个是CoreGraphics提供的C语言层的API,最后一个是OpenGL ES提供的API。
iOS的绘图逻辑代码需要放在UIView的drawRect:方法里面实现,所以绘图只能发生在UIView上面。
绘图后如果我们想要显示图像可以调用
setNeedsDisplay
和setNeedsDisplayInRect:
这两个方法是用来标示一个视图是否需要进行重绘,这里标示重绘并不会马上重新绘制,而是等到该RunLoop上面的任务执行完成后才回执行重绘。
触发重绘有以下几种情况:
1.当遮挡你的视图得其它视图被移动或者删除操作得时候;
2.将视图的hidden属性声明设置为No,使其从隐藏状态变为可见;
3.将视图滚出屏幕,然后重新回到屏幕;
4.显示调用视图的setNeedsDisplay
或者setNeedsDisplayInRect:
方法;
ios绘图周期分析
通过下面这个例子来分析
progressView.hidden = NO;
[self doSomethingTimeConsuming];
progressView.hidden = YES;
第一行代码progress.hidden = NO;根本没有效果,这行代码不会使进度视图在执行耗时操作时显示出来。无论这个方法运行多久,都不会看到视图显示出来。
所有的绘制都发生在主线程,只要代码运行在主线程,就没有东西可以绘制。这就是不要在主线程中执行长时间运行操作的一个原因。这不仅会阻碍绘制更新,还会阻碍事件处理(比如响应触摸事件)。只要代码在主线程上,应用对于用户其实就是“功能挂起的”。如果主线程例程返回足够快,这些变化根本就察觉不到。
你可能会想:“那我就在后台线程运行我的绘图指令。”通常是无法做到这一点的,因为对于当前的UIKit上下文来说绘图不是线程安全的。任何在后台线程修改视图的尝试都会导致未定义的行为,包括绘制出错或崩溃。
这个行为并不是需要解决的问题。绘图时间实质是ios在有限的硬件上渲染复杂绘图的功能。
UIKit绘图
比较简单,这里就说一些常用API。
设置画笔颜色:
画笔颜色分为描边颜色和填充颜色,都是用UIColor的API设置的。在drawRect方法中调用1
2[[UIColor anyColor] setFill]设置填充颜色。
[[UIColor anyColor] setStroke]设置描边颜色。
设置绘图区域:1
2
3UIRectFill(CGRect rect),填充某一区域 。
UIRectFrame(CGRect rect),矩形描边函数。
UIBezierPath,绘图路径类,包括了线段、弧线、矩形、圆形等等。
其中UIBezierPath可以定制主来很多很复杂的图形,这里就不具体的说UIBezierPath的api了,使用起来比较简单直接看文档就可以。
绘制图像
UIImage提供了自己的绘图方法。显示UIImage,除了添加到UIImageView中,还可以直接画到UIView上面,常用API如下:1
2
3-(void)drawAtPoint:(CGPoint)point;在某个点绘制
-(void)drawInRect:(CGRect)rect;绘制到某个矩形中
-(void)drawAsPatternInRect;绘制到某个矩形中并平铺
绘制文字
NSString的category同样提供了绘制文字的功能1
2-(void)drawAtPoint:(CGPoint)point withAttributes:(NSDictionary *)attrs,文本在制定点用属性绘制。
-(void)drawInRect:(CGRect)rect withAttributes:(NSDictionary *)attrs,文本在指定的矩形里绘制。
它们都可以用attrs,这和NSAttributedString很像。
CoreGraphics绘图
绘图上下文CGContextRef,CoreGraphics很类似java、C#等,需要有一个绘图上下文。
上下文中保存了要绘制内容的信息,要获得上下文需要调用。
CGContextRef UIGraphicsGetCurrentContext(void)
常用API
1 | 移动点 |
常用API有很多这里只列举上面这些,剩下的可以查下API
CoreGraphics坐标系
CoreGraphics坐标系和我们平时用UIKit的坐标系是不样的,CoreGraphics的左下角为(0,0)点,而UIKit的左上角为(0,0)点。
所以我们在开发的时候,一般会先同步坐标系(CoreText也需要这么操作),应该这样写
1 | CGContextTranslateCTM(context, 0, img.size.height);平移变化 |
先利用平移变换上移一个视图大小,然后在用缩放变化把高度设-1进行以x为轴的对称变换。
变换
接下来说说变换,绘图是有很多矩阵变换的,其中常用的有以下:
1.平移变换
2.缩放变换
3.旋转变换
4.x轴对称变换
5.y轴对称变换
6.坐标原点对称变换
矩阵变换CTM
CoreGraphics中提供了很多矩阵变换的API,主要有
1 | CGContextRoatateCMT,旋转CTM,旋转变换; |
仿射变换affine
仿射变换是可以重用的变换,通过多次的矩阵乘法得到变换矩阵。1
2
3
4
5
6
7
8CGAffineMakeRotation,创建新的旋转矩阵;
CGAffineMakeScale,创建新的缩放矩阵;
CGAffineMakeTranslation,创建新的平移矩阵;
CGAffineTransform,仿射矩阵,可以经过多次变换;
CGAffineTransformRotate,旋转矩阵;
CGAffineTransformScale,缩放矩阵;
CGAffineTransformTranslate,平移矩阵;
CGContextConcatCTM,连接到CTM变换。
我们可以创建一个CGAffineTransform,然后经过多次的仿射变换后连接到CTM进行显示。