今天看了一下Quartz 2D繪圖,我只想說:不要把繪圖和動畫那些東西當做一個很復雜的東西,其實只要你認真看還是可以理解的。他們并不難。啰嗦了幾句,現在直接進入正題:
前提是我們必須新建一個singleviewapplication。具體新建就不多說了,然后我們自己寫一個UIView的子類,然后創建子類加載到故事板中。(你也可以直接把故事板中的ViewControler的view的父類定義為你自己創建的類),然后我們的操作都是在drawRectangular:方法中實現的:(我采用的是直接修改View的父類為我自定義的類)
下面的就是代碼:我們一個一個來跟著代碼理解:
1、首先是最簡單的填充顏色:
- (void)drawRect:(CGRect)rect {// setFill設置填充的顏色 [[UIColor redColor] setFill]; //隨后需要填充的顏色設置 UIRectFill(rect); //用當前的顏色進行填充}
其中:
setFill方法:它的作用就是設置隨后填充操作用到的顏色。
UIRectFill():該方法就是用剛才設置的顏色進行填充。
結果如下:
我們沒有在ViewController中的修改任何屬性,這只是在自定義的View中完成的。
2、使用UIRectFrame畫一個矩形:
- (void)drawRect:(CGRect)rect { //setStroke設置描邊的顏色 [[UIColor redColor] setStroke]; CGRect frame = CGRectMake(20, 30, 100, 300); UIRectFrame(frame);}
其中:
setStroke:是設置隨后描邊用到的顏色
UIRectFrame():根據指定的rect畫一個框架。
結果如下:
3、然后是NSString類的繪制文本方法:
- (void)drawRect:(CGRect)rect { NSString *s = [NSString stringWithFormat:@"zhangsan"]; //這里面drawAtPoint就是繪制文本的方法 [s drawAtPoint:CGPointMake(100, 300) withAttributes:@{NSFontAttributeName:[UIFont boldSystemFontOfSize:34]}];}
運行效果如下:
其中主要用的的方法就是drawAtPoint:那個方法
另外還有drawInRect方法。具體的方法介紹就不做過多介紹了。
4、畫三角形
- (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):設置當前繪畫狀態 為最近保存的一份狀態??梢岳斫鉃槌鰲2僮?。
使用這兩個函數的原因:有事后需要多次改變圖形上下文對象的參數,這樣兩次繪制就可能相互影響,這就好像拿著蠟筆畫畫,每一次只能拿一個。為了防止相互影響所以要保存上下文設置,繪制完成后我們在用restore那個函數回復圖形上下文。
5、Quartz路徑
Core Graphics中有4種基本圖元用于描述路徑:點、線、弧和貝塞爾(Bezier)曲線。前兩種都不用介紹了都見過,后面的貝塞爾曲線和弧需要說一下。
?。嚎梢杂蓤A心點、半徑、起始角和結束角描述。圓是弧的一個特例。只需要這只起始角度為0,結束角度為360就可以了。
貝塞爾曲線:任何一條曲線都可以通過與他相切的控制線兩端的點的位置定義。具體我也不太理解,先沒看就。如果你理解的深刻可以給我說一下。
6、坐標變換
首先要理解:在Quartz 2D中的坐標系和UIKit坐標系是相反的。什么意思勒?就是
Quartz 2D坐標系原點在左下角,x向右為正方向,y向上為正方向
UIKit坐標系原點在左上角,x向右為正方向,y向下為正方向。
現在就讓我們繼續看看坐標變換把。
--------------------------------為了書寫方便下面的方法我直接提取出來了,只需要在drawRect:方法里面調用就行了--------------------------------
7、畫一張圖片:
//反向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上??纯创a。應該不用過多介紹了。CGContextDrawImage和剛才的CGContextDrawPath類似,只不過畫的東西不一樣罷了。里面要說下CGImageRef:它是一個結構體:封裝了位圖圖像的信息。而UIImaged的CGImage就是返回的這樣的實例。其他不說了。
8、2D圖形基本變換:
有平移變換、縮放變換、旋轉變換、x軸對稱變換、y軸對稱變換、坐標原點對稱變換。具體的都不詳細介紹了。應該都能理解那些變換的意思。
9、CTM變換矩陣
不要看著CTM幾個字母就害怕,其實它就是current transformation matrix的簡稱。就是當前矩陣變換。Quartz 2D提供了多種形式的變換,其中主要是CTM和仿射(Affine)變換??匆幌翪TM吧。
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);}
這個方法是通過仿射變換把剛剛倒過來的圖形放正??梢钥匆幌拢?/p>
CGAFffineTransform就是一個結構體,可以用來接收CGAffineTransformMakeTranslate創建的仿射(平移)矩陣。
然后又CGAffineTransformScale:通過里面的參數來設置縮放矩陣.然后用CGContextConcatCTM連接到CTM變換。這樣就實現了圖像的正過來。drawNormalImage方法實現的效果是一樣的。
----------------------------------------------------這里是結束----------------------------------------------------
沒有了,這里就是結束了。
給個代碼把?好的好的。下面就是源碼:寫的比較亂,能看懂就行了。
http://pan.baidu.com/s/1kTMUyX5
謝謝百度網盤給的空間。
新聞熱點
疑難解答