你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發綜合 >> IOS開發—Quartz 2D介紹

IOS開發—Quartz 2D介紹

編輯:IOS開發綜合

Quartz 2D學習記錄

Quartz 2D簡單介紹

一、什麼是Quartz 2D

Quarz 2D是一個二維繪畫引擎,同時支持ios和mac,其API是Core Graphics框架的,是純C語言的。IOS系統提供的大部分控件的內容都是通過Quartz 2D畫出來的,因此Quartz 2D的一個很重要的價值是:自定義view(自定義UI控件)。

二、一個重要的概念:圖形上下文

圖形上下文(Graphics context)是一個CGContextRef數據,其作用是:

保存繪圖信息、繪圖屬性 繪制目標圖案 輸出繪制好的圖案到輸出目標去,即渲染到什麼地方去(可以是PDF文件、bitmap或者顯示器的窗口上)

這裡寫圖片描述

三、自定義view,即繪制view

在view中實現- (void)drawRect:(CGRect)rect方法,然後在方法中:
1. 取得跟當前view相關聯的圖形上下文;
2. 繪制相應的圖形內容
3. 利用圖形上下文將繪制好的圖形內容渲染顯示到view上面

Quartz 2D簡單使用

代碼示例

    //繪制步驟:1、獲取當前視圖的圖形上下文 2、開始繪圖 3、渲染繪制內容

    /**繪制直線**/

    //1、獲取當前視圖的圖形上下文(圖形上下文決定繪制的輸出目標)
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    //2、開始繪圖
    //設置起點
    CGContextMoveToPoint(ctx, 20, 50);
    //設置終點
    CGContextAddLineToPoint(ctx, 300, 50);
    //設置線條屬性
    //設置顏色
    CGContextSetStrokeColorWithColor(ctx, [UIColor purpleColor].CGColor);
    //另外一種設置顏色的方式
//    [[UIColor purpleColor] set];
    //設置線條寬度
    CGContextSetLineWidth(ctx, 10);
    //設置線條起點和終點的樣式為圓角
    CGContextSetLineCap(ctx, kCGLineCapRound);

    //3、將畫布上繪制的內容渲染到view的layer上
    CGContextStrokePath(ctx);


    /**繪制三角形**/

    //設置起點
    CGContextMoveToPoint(ctx, 150, 80);
    //設置第一個拐點
    CGContextAddLineToPoint(ctx, 220, 150);
    //設置第二個拐點
    CGContextAddLineToPoint(ctx, 80, 150);
    //設置第三個點(終點)
//    CGContextAddLineToPoint(ctx, 150, 80);
    //可以用下面方法代替 縫合起點和終點
    CGContextClosePath(ctx);
    //設置線條的拐點轉角樣式為圓角
    CGContextSetLineJoin(ctx, kCGLineJoinRound);
    //渲染
    CGContextStrokePath(ctx);


    /**繪制空心四邊形**/
    CGContextAddRect(ctx, CGRectMake(40, 200, 200, 100));
    //設置空心(線條)顏色
//    CGContextSetStrokeColorWithColor(ctx, [UIColor lightGrayColor].CGColor);
    //也可以這樣設置顏色
    [[UIColor lightGrayColor] setStroke];
    //設置線條寬度
    CGContextSetLineWidth(ctx, 10);
    //渲染(空心的)
    CGContextStrokePath(ctx);

    /**繪制實心四邊形**/
    CGContextAddRect(ctx, CGRectMake(40, 320, 200, 100));
    //設置實心顏色
//    CGContextSetFillColorWithColor(ctx, [UIColor orangeColor].CGColor);
    [[UIColor orangeColor] setFill];
    //渲染(實心的)
    CGContextFillPath(ctx);

    /**繪制圓(可以用繪制橢圓的方式畫圓)**/
    //參數依次為圓心x,圓心y,半徑,開始位置的弧度,結束位置的弧度,繪制路徑(1為順時針,0為逆時針)
    //由於Quartz2D的坐標系是x軸向右,y軸向上,不同於UIKit坐標系。因此在不將Quartz2D坐標系翻轉的情況下,畫出來的圖形是與原圖形關於x軸對稱的。
    CGContextAddArc(ctx, 100, 520, 50, 0, M_PI_2, 1);
    CGContextStrokePath(ctx); //空心
//    CGContextFillPath(ctx); //實心

    /**繪制橢圓**/
    CGContextAddEllipseInRect(ctx, CGRectMake(230, 400, 120, 200));
    CGContextSetStrokeColorWithColor(ctx, [UIColor blueColor].CGColor);
    CGContextStrokePath(ctx);

    /**繪制弧線**/
//    CGContextAddArcToPoint(ctx, 100, 200, 100, 200, 50);
    CGContextAddArc(ctx, 200, 200, 100, 0, M_PI, 1);
    CGContextSetStrokeColorWithColor(ctx, [UIColor cyanColor].CGColor);
    CGContextStrokePath(ct

繪制結果

這裡寫圖片描述

圖形上下文棧

一、繪制原理

舉個例子,假如要繪制兩條線,一條紅色一條默認的黑色。先繪制紅色線,繪制完畢渲染上去後,再去繪制第二條。繪制第二條的時候如果不重新設置繪畫顏色,那麼繪制出來的線條也是紅色的。也就是說,繪制屬性如果不對其清空(即重新設置)是默認保留在圖形上下文上的。因此可以這樣理解:
一個圖形上下文有3塊區域,分別是繪制屬性,圖像信息,繪制區域:

繪制屬性:包括畫筆的顏色、線條寬度、是否圓角等等; 繪圖信息:比如要繪制一條直線,那麼保存了線條的起點和終點,繪制圓,保存了半徑、中點坐標、起點終點、方向等等。也就是說,繪圖信息中保存的是繪圖路徑,這個在下面會詳細介紹。 繪圖區域:這個區域不是指視圖上的區域,而是圖形上下文上的繪制區域,因為繪畫是在圖形上下文上繪制好之後才被渲染到視圖的制定區域上的。

二、保存圖形上下文繪制屬性

前面說過如果要繪制多個不同屬性的圖形,那麼每次渲染好一個圖形後就要重新設置繪制屬性,通常繪制多個圖形都是這樣做的。有時候可能用到一個簡單的方法:即在繪制一個圖形前先保存當前圖形上下文中的繪制屬性,這個繪制屬性會被保存到圖形上下文棧上,如果下次需要繪制同樣屬性的圖形,直接把這個繪制屬性從棧頂取出來(恢復)就好了。需要注意的是保存一次只能取一次,可以保存多次,但是每次只從棧頂取

代碼示例

/**保存繪制屬性(以繪制3條線為例,第一條第三條屬性一致)**/
//第一條
CGContextMoveToPoint(ctx, 20, 300);
CGContextAddLineToPoint(ctx, 200,300);
//設置繪制屬性
CGContextSetLineWidth(ctx, 10);
CGContextSetLineCap(ctx, kCGLineCapRound);
CGContextSetStrokeColorWithColor(ctx, [UIColor orangeColor].CGColor);
CGContextStrokePath(ctx);

//第二條線
//先保存當前的繪制屬性
CGContextSaveGState(ctx);
CGContextMoveToPoint(ctx, 20, 400);
CGContextAddLineToPoint(ctx, 200, 400);
//設置新的繪制屬性
CGContextSetLineWidth(ctx, 5);
CGContextSetLineCap(ctx, kCGLineCapButt);
CGContextSetStrokeColorWithColor(ctx, [UIColor blueColor].CGColor);
CGContextStrokePath(ctx);

//第三條線
//取出(恢復)之前保存的繪制屬性
CGContextRestoreGState(ctx);
CGContextMoveToPoint(ctx, 20, 500);
CGContextAddLineToPoint(ctx, 200, 500);
CGContextStrokePath(ctx);

繪制結果

這裡寫圖片描述

矩陣操作

一、矩陣操作介紹

矩陣操作主要有旋轉操作、縮放操作、平移操作,是以視圖左上角為原點進行的。對矩陣的操作一定要在繪制之前完成,不然繪制完了再操作無效。

二、代碼說明

    CGContextRef ctx = UIGraphicsGetCurrentContext();

    //矩陣旋轉45度(參數為圖形上下文、旋轉角度)是以左上角為旋轉點的
    //設置矩陣操作要在繪制前完成
//    CGContextRotateCTM(ctx, M_PI_4);

    //縮放(參數為圖形上下文,x方向縮放比例,y方向縮放比例)
//    CGContextScaleCTM(ctx, 0.5, 0.5);

    //平移(參數為圖形上下文,x方向平移距離,y方向平移距離)
    CGContextTranslateCTM(ctx, 100, 100);

    CGContextAddRect(ctx, CGRectMake(100, 100, 100, 100));

    //標記
    NSString *loc1 = @1;
    NSString *loc2 = @2;
    [loc1 drawAtPoint:CGPointMake(99, 99) withAttributes:nil];
    [loc2 drawAtPoint:CGPointMake(201, 99) withAttributes:nil];

    CGContextStrokePath(ctx);

剪切操作

一、剪切介紹

指剪切掉指定區域意外的部分,只保留該區域內的內容。
原則:先設置好剪切區域,或者說剪切方法,再去繪制相關內容。

二、代碼相關

    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //剪切自定義區域意外的部分(以剪切方法為三角形,剪切內容為圖片為例)
//    //    CGContextAddEllipseInRect(ctx, CGRectMake(100, 100, 50, 50));
//    CGContextMoveToPoint(ctx, 100, 100);
//    CGContextAddLineToPoint(ctx, 60, 150);
//    CGContextAddLineToPoint(ctx, 140, 150);
//    CGContextClosePath(ctx);

//    CGContextClip(ctx);

    //剪切指定矩形區域意外的部分
    CGContextClipToRect(ctx, CGRectMake(80, 100, 10, 10));
    UIImage *image = [UIImage imageNamed:@google];
    [image drawAtPoint:CGPointMake(80, 100)];

繪圖路徑

一、繪圖路徑介紹

我們之前畫一條直線,都是直接設置好它的起點和終點,然後就開始畫了。畫一個圓,設置好圓心半徑起點終點和方向即可。事實上,我們設置好這些繪圖信息後,系統會默認創建一條繪圖路徑,畫圖就是根據這條路徑來畫的。一條線對應一條路徑,一個圓對應另一條路徑。那麼我們自然可以通過手動創建路徑的方式繪制,需要繪制幾個圖案,就要創建幾條路徑。

二、注意點

A、Quartz2D中所有通過creat/copy/retain方法創建出來的值都要釋放,以path為例:

CGPathRelease(path);或 CFRelease(path);

B、可以將要繪制的所有路徑加入到圖形上下文後,最後一次性渲染。

三、代碼示例

    //繪制一條直線的兩種方法(兩種方式是等效的)
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextMoveToPoint(ctx, 20, 200);
    CGContextAddLineToPoint(ctx, 300, 200);
    CGContextStrokePath(ctx);

    //手動創建路徑繪制
    //創建一條路徑
    CGMutablePathRef path = CGPathCreateMutable();
    //添加繪圖信息到路徑
    CGPathMoveToPoint(path, NULL, 20, 300);
    CGPathAddLineToPoint(path, NULL, 300, 300);
    //將路徑添加到圖形上下文
    CGContextAddPath(ctx, path);


    //創建另一條路徑
    CGMutablePathRef path2 = CGPathCreateMutable();
    CGPathAddEllipseInRect(path2, NULL, CGRectMake(100, 400, 100, 100));
    CGContextAddPath(ctx, path2);
    CGContextStrokePath(ctx);

    //渲染所有路徑對應的圖案
    CGContextStrokePath(ctx);

    //Quartz2D中所有通過creat/copy/retain方法創建出來的值都要釋放
    CGPathRelease(path);
    CGPathRelease(path2);
    //或者
//    CFRelease(path);

運行結果

這裡寫圖片描述

Bitmap

一、bitmap圖形上下文

Quartz2D提供了以下幾種類型的圖形上下文

Bitmap Graphics Context PDF Graphics Context Window Graphics Context Layer Graphics Context Printer Graphics Context

常用的是Bitmap Graphics Context。所謂Bitmap,其實就是UIImage,這也是最常用到的圖形上下文,通常用它來生成一張圖片。步驟如下:

創建一個bitmap圖形上下文(有兩種方式)
A.UIGraphicsBeginImageContext(<#CGSize size#>);
B.UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale);

這兩種方法都可以創建一個bitmap圖形上下文,但是第一種創建的圖片清晰度和質量沒有第二種好。方法二接收的參數依次為:

size:指定創建出來的bitmap尺寸大小 opaque:是否透明,YES表示不透明,NO透明 scale:縮放比例,0為不縮放

獲取創建好的bitmap圖形上下文然後在上面做文章(畫圖)

取出繪制好的圖片 關閉bitmap圖形上下文 釋放需要釋放的變量

代碼示例(截屏)

//點擊按鈕截屏
- (void)actionShot:(UIButton *)sender{

    //可以隱藏按鈕,渲染完後顯示回來
    self.buttonShot.hidden = YES;

    //創建圖形上下文
    UIGraphicsBeginImageContextWithOptions(CGSizeMake(self.view.frame.size.width, self.view.frame.size.height), NO, 0);
    //獲取圖形上下文並將當前屏幕渲染到圖形上下文上
    AppDelegate *delegate = (AppDelegate *)[UIApplication sharedApplication].delegate;
    [delegate.window .layer renderInContext:UIGraphicsGetCurrentContext()];
    //從圖形上下文中取出繪制好的圖片
    UIImage *screenImage = UIGraphicsGetImageFromCurrentImageContext();
    //關閉圖形上下文
    UIGraphicsEndImageContext();

    self.buttonShot.hidden = NO;

//    //截屏完畢 有時候可能想獲取屏幕中指定區域的圖片,如下操作
//    //得到截屏的cgimage
    CGImageRef image = screenImage.CGImage;

    //設置目標區域,注意這裡需要考慮retina分辨率的放大倍數,以iphone6plus為例,在原尺寸的基礎上*3,這裡就不判斷了。
    CGRect rect = CGRectMake(0, 0, screenImage.size.width*3, screenImage.size.height*3);
    //取出目標區域的圖片
    CGImageRef targetImage = CGImageCreateWithImageInRect(image, rect);
    //最終圖片
    UIImage *finalImage = [UIImage imageWithCGImage:targetImage];


    //保存到相冊
    UIImageWriteToSavedPhotosAlbum(finalImage, self, @selector(image: didFinishSavingWithError:contextInfo:), nil);

    //保存到沙盒
    NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject];
    NSDateFormatter *dateFormatter = [[NSDateFormatter alloc]init];
    [dateFormatter setDateFormat:@yyyy-MM-dd HH:mm:ss];
    NSString *currentTime = [dateFormatter stringFromDate:[NSDate date]];
    NSString *imagePath = [path stringByAppendingPathComponent:[NSString stringWithFormat:@ScreenShot_%@.png,currentTime]];
    NSData *imageDate = UIImagePNGRepresentation(finalImage);
    [imageDate writeToFile:imagePath atomically:YES];

    CGImageRelease(targetImage);
}
//保存至相冊後的回調
- (void)image: (UIImage *) image didFinishSavingWithError: (NSError *) error contextInfo: (void *) contextInfo
{
    NSString *msg = nil ;
    if(error != NULL){
        msg = @保存圖片失敗 ;
    }else{
        msg = @保存圖片成功 ;
    }
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@保存圖片結果提示
                                                    message:msg
                                                   delegate:self
                                          cancelButtonTitle:@確定
                                          otherButtonTitles:nil];
    [alert show];
}

Quartz2D內存管理

前面講繪圖路徑的時候提到過內存管理,下面再總結一下:

凡是使用含有“create”或“copy”的函數創建的對象,使用完畢後必需釋放,否則將導致內存洩露。不含“create”或“copy”的則不需要釋放。 如果retain了一個對象,不再使用時需要release。已CGColorSpace為例,如果創建了一個CGColorSpace對象,則使用函數CGColorSpaceRetain和CGColorSpaceRelease來retain和release對象。也可以使用Core Foundation的CFRetain和CFRelease。注意不能傳遞NULL值給這些函數。

 

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved