Quartz 2d繪圖

今天看了一下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

謝謝百度網盤給的空間。

相關文章
相關標籤/搜索