首页 > 学院 > 开发设计 > 正文

iOS绘图

2019-11-14 18:31:48
字体:
来源:转载
供稿:网友

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方法中调用

[[UIColor anyColor] setFill]设置填充颜色。[[UIColor anyColor] setStroke]设置描边颜色。

设置绘图区域:

UIRectFill(CGRect rect),填充某一区域 。UIRectFrame(CGRect rect),矩形描边函数。UIBezierPath,绘图路径类,包括了线段、弧线、矩形、圆形等等。

其中UIBezierPath可以定制主来很多很复杂的图形,这里就不具体的说UIBezierPath的api了,使用起来比较简单直接看文档就可以。

绘制图像

UIImage提供了自己的绘图方法。显示UIImage,除了添加到UIImageView中,还可以直接画到UIView上面,常用API如下:

-(void)drawAtPoint:(CGPoint)point;在某个点绘制-(void)drawInRect:(CGRect)rect;绘制到某个矩形中-(void)drawaspatternInRect;绘制到某个矩形中并平铺

绘制文字

NSString的category同样提供了绘制文字的功能 

-(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

移动点void CGContextMoveToPoint(CGContextRef c, CGFloat x, CGFloat y)画线void CGContextAddLineToPoint(CGContextRef c, CGFloat x, CGFloat y)闭合路径void CGContextClosePath(CGContextRef c)绘制路径void CGContextDrawPath(CGContextRef c, CGPathDrawingMode mode)设置描边颜色void CGContextSetStrokeColorWithColor(CGContextRef c, CGColorRef color)设置填充颜色void CGContextSetFillColorWithColor(CGContextRef c, CGColorRef color)绘制贝塞尔曲线,这里的参数分别是两个控制点和交点的左边,大家可以自行百度贝塞尔曲线定义void CGContextAddCurveToPoint(CGContextRef c, CGFloat cp1x,CGFloat cp1y, CGFloat cp2x, CGFloat cp2y, CGFloat x, CGFloat y)保存上下文void CGContextSaveGState(CGContextRef c)读取上下文void CGContextRestoreGState(CGContextRef c)

 常用API有很多这里只列举上面这些,剩下的可以查下API

 

CoreGraphics坐标系

CoreGraphics坐标系和我们平时用UIKit的坐标系是不样的,CoreGraphics的左下角为(0,0)点,而UIKit的左上角为(0,0)点。

所以我们在开发的时候,一般会先同步坐标系(CoreText也需要这么操作),应该这样写

CGContextTranslateCTM(context, 0, img.size.height);平移变化CGContextScaleCTM(context,1,-1);缩放变换

先利用平移变换上移一个视图大小,然后在用缩放变化把高度设-1进行以x为轴的对称变换。

 

变换

接下来说说变换,绘图是有很多矩阵变换的,其中常用的有以下:

1.平移变换

2.缩放变换

3.旋转变换

4.x轴对称变换

5.y轴对称变换

6.坐标原点对称变换

矩阵变换CTM

CoreGraphics中提供了很多矩阵变换的API,主要有

CGContextRoatateCMT,旋转CTM,旋转变换;CGContextScaleCTM,缩放变换;CGContextTranslateCTM,平移变换。

仿射变换affine

仿射变换是可以重用的变换,通过多次的矩阵乘法得到变换矩阵。

CGAffineMakeRotation,创建新的旋转矩阵;CGAffineMakeScale,创建新的缩放矩阵;CGAffineMakeTranslation,创建新的平移矩阵;CGAffineTransform,仿射矩阵,可以经过多次变换;CGAffineTransformRotate,旋转矩阵;CGAffineTransformScale,缩放矩阵;CGAffineTransformTranslate,平移矩阵;CGContextConcatCTM,连接到CTM变换。

我们可以创建一个CGAffineTransform,然后经过多次的仿射变换后连接到CTM进行显示。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表