今天看了一下Quartz 2D绘图,我只想说:不要把绘图和动画那些东西当作一个很复杂的东西,其实只要你认真看仍是能够理解的。他们并不难。啰嗦了几句,如今直接进入正题:框架
前提是咱们必须新建一个singleviewApplication。具体新建就很少说了,而后咱们本身写一个UIView的子类,而后建立子类加载到故事板中。(你也能够直接把故事板中的ViewControler的view的父类定义为你本身建立的类),而后咱们的操做都是在drawRectangular:方法中实现的:(我采用的是直接修改View的父类为我自定义的类)函数
下面的就是代码:咱们一个一个来跟着代码理解:动画
一、首先是最简单的填充颜色:spa
- (void)drawRect:(CGRect)rect { // setFill设置填充的颜色 [[UIColor redColor] setFill]; //随后须要填充的颜色设置 UIRectFill(rect); //用当前的颜色进行填充 }
其中:3d
setFill方法:它的做用就是设置随后填充操做用到的颜色。rest
UIRectFill():该方法就是用刚才设置的颜色进行填充。code
结果以下:orm
咱们没有在ViewController中的修改任何属性,这只是在自定义的View中完成的。对象
二、使用UIRectFrame画一个矩形:blog
- (void)drawRect:(CGRect)rect { //setStroke设置描边的颜色 [[UIColor redColor] setStroke]; CGRect frame = CGRectMake(20, 30, 100, 300); UIRectFrame(frame); }
其中:
setStroke:是设置随后描边用到的颜色
UIRectFrame():根据指定的rect画一个框架。
结果以下:
三、而后是NSString类的绘制文本方法:
- (void)drawRect:(CGRect)rect { NSString *s = [NSString stringWithFormat:@"zhangsan"]; //这里面drawAtPoint就是绘制文本的方法 [s drawAtPoint:CGPointMake(100, 300) withAttributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:34]}]; }
运行效果以下:
其中主要用的的方法就是drawAtPoint:那个方法
另外还有drawInRect方法。具体的方法介绍就不作过多介绍了。
四、画三角形
- (void)drawRect:(CGRect)rect { CGContextRef context = UIGraphicsGetCurrentContext(); //建立图形上下文
CGContextSaveGState(context); //保存当前图形上下文设置 CGContextMoveToPoint(context, 20, 20); CGContextAddLineToPoint(context, 40, 100); CGContextAddLineToPoint(context, 160, 20); CGContextClosePath(context); [[UIColor redColor] setFill]; [[UIColor blackColor] setStroke]; CGContextDrawPath(context, kCGPathFillStroke);
CGContextRestoreGState(context); //恢复图形上下文设置 }
效果以下:
其中遇到了新的东西:CGContextRef。不要惧怕遇到CG,其实很简单。
首先,一句
CGContextRef context = UIGraphicsGetCurrentContext(); //建立图形上下文
建立了上下文,什么是上下文?????你能够直接把他理解成一个Quartz 2D的绘画环境。
就是对每一个的绘画操做都须要一个绘画环境,而后才能进行绘画操做。而UIGraphicsGetCurrentContext()就是获取当前的绘画环境,
而后里面有:
CGContextMoveToPoint:就是绘画的起始点。
CGContextAddLineToPoint:就是从刚才绘画起始点到你在这个函数中指定的点。
最后用CGContextClosePath去封闭这三个点组成的图形。这样一个三角形就出来。
NO,NO,还须要CGContextDrawPath来进行操做哦。它的做用是绘制当前路径用提供的绘制模型:这里用的kCGPathFillStroke,就是描边填充模型,其余的模型读者能够本身查看。
忘了,忘了。还有两个方法没介绍:
CGContextSaveGState(context):它的做用是为当前的上下文保存一个复制。官方介绍是压一份复制的当前绘画状态到绘画状态栈中。也就是压栈操做。
CGContextRestoreGState(context):设置当前绘画状态 为最近保存的一份状态。能够理解为出栈操做。
使用这两个函数的缘由:有过后须要屡次改变图形上下文对象的参数,这样两次绘制就可能相互影响,这就好像拿着蜡笔画画,每一次只能拿一个。为了防止相互影响因此要保存上下文设置,绘制完成后咱们在用restore那个函数回复图形上下文。
五、Quartz路径
Core Graphics中有4种基本图元用于描述路径:点、线、弧和贝塞尔(Bezier)曲线。前两种都不用介绍了都见过,后面的贝塞尔曲线和弧须要说一下。
弧:能够由圆心点、半径、起始角和结束角描述。圆是弧的一个特例。只须要这只起始角度为0,结束角度为360就能够了。
贝塞尔曲线:任何一条曲线均可以经过与他相切的控制线两端的点的位置定义。具体我也不太理解,先没看就。若是你理解的深入能够给我说一下。
六、坐标变换
首先要理解:在Quartz 2D中的坐标系和UIKit坐标系是相反的。什么意思勒?就是
Quartz 2D坐标系原点在左下角,x向右为正方向,y向上为正方向
UIKit坐标系原点在左上角,x向右为正方向,y向下为正方向。
如今就让咱们继续看看坐标变换把。
--------------------------------为了书写方便下面的方法我直接提取出来了,只须要在drawRect:方法里面调用就好了--------------------------------
七、画一张图片:
//反向image - (void)drawImage { /* 图形的另外一种操做就是变换:包括评议、缩放和旋转等形式的变换 Quartz 2D坐标系和UIKit坐标系是相反的。 */ CGContextRef context = UIGraphicsGetCurrentContext(); UIImage *image = [UIImage imageNamed:@"test"]; CGImageRef cgImage = image.CGImage; CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height); CGContextDrawImage(context, rect, cgImage); //因为坐标系相反,因此图形是返回来的。 }
运行一下看看:
这图片怎么长这样,我开始也纳闷,后来知道了,原来它是倒着放的。由于什么呢?由于Quartz 2D坐标系和UIKit的相反,因此会形成这种状况。
先无论反正了。反正画了一个图片到view上。看看代码。应该不用过多介绍了。CGContextDrawImage和刚才的CGContextDrawPath相似,只不过画的东西不同罢了。里面要说下CGImageRef:它是一个结构体:封装了位图图像的信息。而UIImaged的CGImage就是返回的这样的实例。其余不说了。
八、2D图形基本变换:
有平移变换、缩放变换、旋转变换、x轴对称变换、y轴对称变换、坐标原点对称变换。具体的都不详细介绍了。应该都能理解那些变换的意思。
九、CTM变换矩阵
不要看着CTM几个字母就惧怕,其实它就是current transformation matrix的简称。就是当前矩阵变换。Quartz 2D提供了多种形式的变换,其中主要是CTM和仿射(Affine)变换。看一下CTM吧。
CTM主要涉及的函数有:
CGContextRotateCTM:旋转变换
CGContextScaleCTM:缩放变换
CGContextTranslateCTM:平移变换
举个简单栗子:
- (void)tanslateImage { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); UIImage *image = [UIImage imageNamed:@"test"]; CGImageRef cgImage = image.CGImage; // CGContextTranslateCTM(context, 0, image.size.height); // CGContextScaleCTM(context, -1, 1); CGContextTranslateCTM(context, 50, 50); //移动它的位置到100,50 // CGContextRotateCTM(context, 360); CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height); CGContextDrawImage(context, rect, cgImage); CGContextRestoreGState(context); }
看看结果:
使用了CGContextTranslateCTM,咱们能够进行位置调整。这里我把位置向右向下移动了50.就成这样了。哪些旋转和缩小就不说了,本身尝试一把。
这里给出来代码,能够试试:
/**旋转变换*/
#define radians(x) (x*M_PI/180)
- (void)rotateImage { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); UIImage *image = [UIImage imageNamed:@"test"]; CGImageRef cgImage = image.CGImage; CGContextRotateCTM(context, radians(-45.)); CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height); CGContextDrawImage(context, rect, cgImage); CGContextRestoreGState(context); }
/**缩小变换*/ - (void)scaleImage { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); UIImage *image = [UIImage imageNamed:@"test"]; CGImageRef cgImage = image.CGImage; CGContextScaleCTM(context, .2, .40); //设置缩小大小 CGRect rect = CGRectMake(0, image.size.height, image.size.width, image.size.height); CGContextDrawImage(context, rect, cgImage); }
最后再给出一个比较厉害的让你的图片旋转过来的方法:
//正向image - (void)drawNormalImage { CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); //保留初始上下文 UIImage *image = [UIImage imageNamed:@"test"]; CGImageRef cgImage = image.CGImage; CGContextTranslateCTM(context, 0, image.size.height); //先作平移变换 CGContextScaleCTM(context, 1, -1); //缩放变换x不变,y相反 CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height); CGContextDrawImage(context, rect, cgImage); CGContextRestoreGState(context); //还原初始上下文 // CGContextScaleCTM(context, -1, 1); // CGContextDrawImage(context, rect, cgImage); }
其实让图片正过来很简单,先作了平移变换,而后又缩放了一把,就0k了。
------------------------------------------------看累了吗?继续看。立刻完--------------------------------
仿射变换(Affine)
也是一种2D变换,他能够重用变换,通过屡次变换,每一种变换均可以用矩阵表示,经过屡次矩阵相乘获得最后结果。(矩阵太难了。。。。。。。。。不要紧,理解就好了)
下面是一些访射变换函数:
CGAffineMakeRotation:建立新的旋转变换矩阵
CGAffineMakeScale:建立新的 缩放矩阵函数
CGAffineMakeTranslation:建立新的平移矩阵
CGAffineTransformRotate:旋转矩阵
CGAffineTransformScale:缩放矩阵
CGAffineTransformTranslate:平移矩阵
CGContextConcatCTM:链接到CTM变换。
这么多函数。这么多函数。这么多函数。太难了。。。。。。不过没事。看看下面的例子你应该就能够理解了。
- (void)normalImageByAffine { UIImage *image = [UIImage imageNamed:@"test"]; CGImageRef cgImage = image.CGImage; CGContextRef context = UIGraphicsGetCurrentContext(); CGContextSaveGState(context); CGAffineTransform myAffine = CGAffineTransformMakeTranslation(0, image.size.height); myAffine = CGAffineTransformScale(myAffine, 1, -1); CGContextConcatCTM(context, myAffine); CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height); CGContextDrawImage(context, rect, cgImage); CGContextRestoreGState(context); }
这个方法是经过仿射变换把刚刚倒过来的图形放正。能够看一下:
CGAFffineTransform就是一个结构体,能够用来接收CGAffineTransformMakeTranslate建立的仿射(平移)矩阵。
而后又CGAffineTransformScale:经过里面的参数来设置缩放矩阵.而后用CGContextConcatCTM链接到CTM变换。这样就实现了图像的正过来。drawNormalImage方法实现的效果是同样的。
----------------------------------------------------这里是结束----------------------------------------------------
没有了,这里就是结束了。
给个代码把?好的好的。下面就是源码:写的比较乱,能看懂就好了。
http://pan.baidu.com/s/1kTMUyX5
谢谢百度网盘给的空间。