iOS Quartz 2D 學習

Quartz 2D是iOS常用繪圖框架,Quartz 2D是Core Graphics框架的一部分,是一個二維圖像繪制引擎。Quartz 2D在UIKit中也有封裝和集成,我們日常開發時所用到的UIKit中的組件都是由Core Graphics進行繪制的。不僅如此,當我們引入UIKit框架時系統會自動引入Core Graphics框架,并且為了方便開發者使用在UIKit內部還對一些常用的繪圖API進行了封裝。
?一般分為以下幾個步驟:
?一、獲取繪圖上下文
?二、創建并設置路徑(1、創建路徑,2、設置路徑起點,3、增加路徑內容)
?三、將路徑添加到上下文
?四、設置上下文狀態(1、設置邊線顏色,2、設置填充顏色,3、設置線寬,4、設置線段連接樣式,5、設置線段首位樣式,6、設置虛線樣式)
?五、繪制路徑
?六、釋放路徑
圖形上下文CGContextRef代表圖形輸出設備(也就是繪制的位置),包含了繪制圖形的一些設備信息,Quartz 2D中的所有對象最終都必須繪制到圖形上下文。在Quartz 2D中的繪圖上下文可以是位圖Bitmap、PDF、窗口Window、層Layer、打印對象Printer。

繪制圖形

UIKit中默認已經為我們準備好了一個圖形上下文對象,在UI控件的drawRect:方法(這個方法在loadView、viewDidLoad方法后執行)中我們可以通過UIKit封裝函數UIGraphicsGetCurrentContext()方法獲得這個圖形上下文(注意在其他UI控件方法中無法取得這個對象),然后我們只要按照繪圖步驟一步步執行即可。

繪制直線
- (void)drawRect:(CGRect)rect {
    
    // 1、獲得圖形上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    // 2、繪制路徑(相當于前面創建路徑并添加路徑到圖形上下文兩步操作)
    CGContextMoveToPoint(context, 40, 50);
    CGContextAddLineToPoint(context, 40, 100);
    CGContextSetLineWidth(context, 2.0); // 設置線寬
    
    // 3、設置圖形上下文屬性
    [[UIColor redColor] setStroke]; // 設置紅色邊框
    
    // 4、繪制路徑
    CGContextDrawPath(context, kCGPathFillStroke);
}
繪制矩形
- (void)drawRect:(CGRect)rect {
    
    // 1、獲得圖形上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    // 2、繪制路徑(相當于前面創建路徑并添加路徑到圖形上下文兩步操作)
    CGContextMoveToPoint(context, 40, 50);
    CGContextAddLineToPoint(context, 40, 100);
    CGContextAddLineToPoint(context, 140, 100);
    CGContextAddLineToPoint(context, 140, 50);
    CGContextClosePath(context); // 封閉路徑
    CGContextSetLineWidth(context, 2.0); // 設置線寬
    
    // 3、設置圖形上下文屬性
    [[UIColor redColor] setStroke]; // 設置紅色邊框
    [[UIColor greenColor] setFill]; // 設置綠色填充
//    [[UIColor blueColor] set]; // 同時設置填充和邊框色
    
    // 4、繪制路徑
    CGContextDrawPath(context, kCGPathFillStroke);
}

- (void)drawRect:(CGRect)rect {
    // 獲得圖形上下文
    CGContextRef context = UIGraphicsGetCurrentContext();
    //添加矩形對象
    CGRect myRect = CGRectMake(20, 50, 200, 50);
    CGContextAddRect(context, myRect);
    //設置屬性
    [[UIColor redColor] set];
    //繪制
    CGContextDrawPath(context, kCGPathFillStroke);
}

// UIKit對繪圖方法的封裝
- (void)drawRect:(CGRect)rect {
    CGRect rect1 = CGRectMake(20, 100, 200, 50);
    CGRect rect2 = CGRectMake(20, 200, 200, 50);
    // 設置屬性
    [[UIColor yellowColor] set];
    // 繪制矩形,相當于創建對象、添加對象到上下文、繪制三個步驟
    UIRectFill(rect1); // 繪制矩形(只有填充)
    [[UIColor redColor] setStroke];
    UIRectFrame(rect2); // 繪制矩形(只有邊框)
}

繪制圓
- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    // 添加對象,繪制橢圓(圓形)的過程也是先創建一個矩形
    CGRect rect1 = CGRectMake(50, 50, 220.0, 200.0);
    CGContextAddEllipseInRect(context, rect1);
    // 設置屬性
    [[UIColor greenColor] set];
    // 繪制
    CGContextDrawPath(context, kCGPathFillStroke);
}
繪制弧形
- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    // 添加弧形對象 x:中心點x坐標 y:中心點y坐標 radius:半徑 startAngle:起始弧度endAngle:終止弧度 closewise:是否逆時針繪制,0則順時針繪制
    CGContextAddArc(context, 160, 160, 100.0, 0.0, M_PI, 1);
    // 設置屬性
    [[UIColor yellowColor] set];
    // 繪制
    CGContextDrawPath(context, kCGPathFillStroke);
}
繪制貝塞爾曲線

不規則圖形我們需要利用路徑。而曲線繪制屬于路徑繪制。Quartz 2D中曲線繪制分為兩種:二次貝塞爾曲線和三次貝塞爾曲線。二次曲線只有一個控制點,而三次曲線有兩個控制點。


貝塞爾曲線圖.png
- (void)drawRect:(CGRect)rect {
    
    CGContextRef context = UIGraphicsGetCurrentContext();
    // 繪制曲線
    CGContextMoveToPoint(context, 40, 100); // 起始位置
    // 繪制二次貝塞爾曲線 c:圖形上下文 cpx:控制點x坐標 cpy:控制點y坐標 x:結束點x坐標 y:結束點y坐標
    CGContextAddQuadCurveToPoint(context, 120, 10, 300, 100);
    
    CGContextMoveToPoint(context, 40, 500);
    // 繪制三次貝塞爾曲線 c:圖形上下文 cp1x:第一個控制點x坐標 cp1y:第一個控制點y坐標 cp2x:第二個控制點x坐標 cp2y:第二個控制點y坐標 x:結束點x坐標 y:結束點y坐標
    CGContextAddCurveToPoint(context, 80, 200, 240, 400, 200, 200);
    
    //設置圖形上下文屬性
    [[UIColor greenColor] setFill];
    [[UIColor redColor] setStroke];
    
    //繪制路徑
    CGContextDrawPath(context, kCGPathFillStroke);
}
繪制文字
- (void)drawRect:(CGRect)rect {

    //繪制到指定的區域內容
    NSString *str = @"文字繪制 哈哈哈";
    CGRect rect1 = CGRectMake(20, 100, 300, 300);
    UIFont *font = [UIFont systemFontOfSize:28];//設置字體
    UIColor *color = [UIColor blueColor];//字體顏色
    NSMutableParagraphStyle *style = [[NSMutableParagraphStyle alloc] init];//段落樣式
    NSTextAlignment align = NSTextAlignmentLeft;//對齊方式
    style.alignment = align;
    [str drawInRect:rect1 withAttributes:@{NSFontAttributeName:font,NSForegroundColorAttributeName:color,NSParagraphStyleAttributeName:style}];
   
}
繪制圖片
- (void)drawRect:(CGRect)rect {

    UIImage *image = [UIImage imageNamed:@"image_1.jpg"];
    // 從某一點開始繪制
    [image drawAtPoint:CGPointMake(30, 50)];
    // 繪制到指定的矩形中,注意如果大小不合適會會進行拉伸
//    [image drawInRect:CGRectMake(10, 50, 300, 450)];
    // 平鋪繪制
//    [image drawAsPatternInRect:CGRectMake(0, 0, 320, 568)];
   
}

- (void)drawRect:(CGRect)rect {
    
    CGContextRef context = UIGraphicsGetCurrentContext();
    UIImage *image = [UIImage imageNamed:@"image_1.jpg"];
    CGSize size = [UIScreen mainScreen].bounds.size;
    CGContextSaveGState(context);
    // 上下文形變
    CGContextScaleCTM(context, 1.0, -1.0); // 在y軸縮放-1相當于沿著x張旋轉180
    CGContextTranslateCTM(context, 0, -(size.height-(size.height-2*50-450))); // 向上平移
    // 圖像繪制
    CGRect rect1 = CGRectMake(10, 50, 300, 450);
    CGContextDrawImage(context, rect1, image.CGImage);
    
    CGContextRestoreGState(context);
}
繪制漸變填充

Quartz 2D的漸變方式分為兩種:
?a.線性漸變線:漸變色以直線方式從開始位置逐漸向結束位置漸變
?b.徑向漸變:以中心點為圓心從起始漸變色向四周輻射,直到終止漸變色
?使用Quartz 2D繪圖時我們的顏色除了使用常規的方法(如何前面CGContextSetRGBFillColor(CGContextRef context, CGFloat red, CGFloat green, CGFloat blue, CGFloat alpha)方法)設置RGB和透明度外,顏色參數也可能是一個數組。如使用顏色空間填充時用到的CGContextSetFillColor(CGContextRef context, const CGFloat *components)方法,這個時候components數組中具體是如何存儲顏色就要根據顏色空間而定,如果顏色空間使用RGB則數組中的元素四個為一組,分別是red(紅)、green(綠)、blue(藍)、alpha(透明度)。

// 線性漸變
- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    // 使用rgb顏色空間
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    
    /* 指定漸變色 space:顏色空間 components:顏色數組,注意由于指定了RGB顏色空間,
    那么四個數組元素表示一個顏色(red、green、blue、alpha),如果有四個顏色則這個數組有4*4個元素 locations:顏色所在位置(范圍0~1)
    ,這個數組的個數不小于components中存放顏色的個數 count:漸變個數,等于locations的個數
    */
    CGFloat compoents[16] = {
        255.0/255.0, 86.0/255.0, 255.0/255.0, 1,
        255.0/255.0, 127.0/255.0, 255.0/255.0, 1,
        255.0/255.0, 200.0/255.0, 12.0/255.0, 1,
        1.0, 1.0, 1.0, 1.0
    };
    CGFloat locations[4] = {0, 0.3, 0.6, 1.0};
    CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, compoents, locations, 4);
    
    /* 繪制線性漸變 context:圖形上下文 gradient:漸變色 startPoint:起始位置 endPoint:終止位置 options:繪制方式,
    kCGGradientDrawsBeforeStartLocation 開始位置之前就進行繪制,到結束位置之后不再繪制,
    kCGGradientDrawsAfterEndLocation開始位置之前不進行繪制,到結束點之后繼續填充*/
    CGContextDrawLinearGradient(context, gradient, CGPointZero, CGPointMake(320, 300), kCGGradientDrawsAfterEndLocation);
    
    //釋放顏色空間
    CGColorSpaceRelease(colorSpace);
}

// 徑向漸變
- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    //使用rgb顏色空間
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    
    /* 指定漸變色
     space:顏色空間
     components:顏色數組,注意由于指定了RGB顏色空間,那么四個數組元素表示一個顏色(red、green、blue、alpha),
     如果有四個顏色則這個數組有4*4個元素
     locations:顏色所在位置(范圍0~1),這個數組的個數不小于components中存放顏色的個數
     count:漸變個數,等于locations的個數
    */
    CGFloat compoents[16] = {
        248.0/255.0, 86.0/255.0, 86.0/255.0, 1,
        249.0/255.0, 127.0/255.0, 127.0/255.0, 1,
        255.0/255.0, 233.0/255.0, 127.0/255.0, 1,
        1.0, 1.0, 1.0, 1.0
    };
    CGFloat locations[4] = {0, 0.3, 0.6, 1.0};
    CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, compoents, locations, 4);
    
    /*繪制徑向漸變
     context:圖形上下文
     gradient:漸變色
     startCenter:起始點位置
     startRadius:起始半徑(通常為0,否則在此半徑范圍內容無任何填充)
     endCenter:終點位置(通常和起始點相同,否則會有偏移)
     endRadius:終點半徑(也就是漸變的擴散長度)
     options:繪制方式,kCGGradientDrawsBeforeStartLocation 開始位置之前就進行繪制,但是到結束位置之后不再繪制,
     kCGGradientDrawsAfterEndLocation開始位置之前不進行繪制,但到結束點之后繼續填充
     */
    CGContextDrawRadialGradient(context, gradient, CGPointMake(160, 284),0, CGPointMake(165, 289), 150, kCGGradientDrawsAfterEndLocation);
    //釋放顏色空間
    CGColorSpaceRelease(colorSpace);
}
疊加模式

Quartz 2D繪圖時后面繪制的圖像會覆蓋前面的,默認情況下如果前面的被覆蓋后將看不到后面的內容,但是有時候這個結果并不是我們想要的,因此在Quartz 2D中提供了填充模式供開發者配置調整。

/* 使用UIKit的封裝方法進行疊加模式設置,
一般的方法當然是使用CGContextSetBlendMode(CGContextRef context, CGBlendMode mode)方法進行設置。*/
- (void)drawRect:(CGRect)rect {
        CGRect rect50 = CGRectMake(0, 130.0, 320.0, 50.0);
        CGRect rect1 = CGRectMake(0, 390.0, 320.0, 50.0);
        CGRect rect2 = CGRectMake(20, 50.0, 10.0, 250.0);
        CGRect rect3 = CGRectMake(40.0, 50.0, 10.0, 250.0);
        CGRect rect4 = CGRectMake(60.0, 50.0, 10.0, 250.0);
        CGRect rect5 = CGRectMake(80.0, 50.0, 10.0, 250.0);
        CGRect rect6 = CGRectMake(100.0, 50.0, 10.0, 250.0);
        CGRect rect7 = CGRectMake(120.0, 50.0, 10.0, 250.0);
        CGRect rect8 = CGRectMake(140.0, 50.0, 10.0, 250.0);
        CGRect rect9 = CGRectMake(160.0, 50.0, 10.0, 250.0);
        CGRect rect10 = CGRectMake(180.0, 50.0, 10.0, 250.0);
        CGRect rect11 = CGRectMake(200.0, 50.0, 10.0, 250.0);
        CGRect rect12 = CGRectMake(220.0, 50.0, 10.0, 250.0);
        CGRect rect13 = CGRectMake(240.0, 50.0, 10.0, 250.0);
        CGRect rect14 = CGRectMake(260.0, 50.0, 10.0, 250.0);
        CGRect rect15 = CGRectMake(280.0, 50.0, 10.0, 250.0);
        
        CGRect rect16 = CGRectMake(30.0, 310.0, 10.0, 250.0);
        CGRect rect17 = CGRectMake(50.0, 310.0, 10.0, 250.0);
        CGRect rect18 = CGRectMake(70.0, 310.0, 10.0, 250.0);
        CGRect rect19 = CGRectMake(90.0, 310.0, 10.0, 250.0);
        CGRect rect20 = CGRectMake(110.0, 310.0, 10.0, 250.0);
        CGRect rect21 = CGRectMake(130.0, 310.0, 10.0, 250.0);
        CGRect rect22 = CGRectMake(150.0, 310.0, 10.0, 250.0);
        CGRect rect23 = CGRectMake(170.0, 310.0, 10.0, 250.0);
        CGRect rect24 = CGRectMake(190.0, 310.0, 10.0, 250.0);
        CGRect rect25 = CGRectMake(210.0, 310.0, 10.0, 250.0);
        CGRect rect26 = CGRectMake(230.0, 310.0, 10.0, 250.0);
        CGRect rect27 = CGRectMake(250.0, 310.0, 10.0, 250.0);
        CGRect rect28 = CGRectMake(270.0, 310.0, 10.0, 250.0);
        CGRect rect29 = CGRectMake(290.0, 310.0, 10.0, 250.0);
        
        [[UIColor yellowColor] set];
        UIRectFill(rect50);

        [[UIColor greenColor] setFill];
        UIRectFill(rect1);
        
        [[UIColor redColor] setFill];
        UIRectFillUsingBlendMode(rect2, kCGBlendModeClear);
        UIRectFillUsingBlendMode(rect3, kCGBlendModeColor);
        UIRectFillUsingBlendMode(rect4, kCGBlendModeColorBurn);
        UIRectFillUsingBlendMode(rect5, kCGBlendModeColorDodge);
        UIRectFillUsingBlendMode(rect6, kCGBlendModeCopy);
        UIRectFillUsingBlendMode(rect7, kCGBlendModeDarken);
        UIRectFillUsingBlendMode(rect8, kCGBlendModeDestinationAtop);
        UIRectFillUsingBlendMode(rect9, kCGBlendModeDestinationIn);
        UIRectFillUsingBlendMode(rect10, kCGBlendModeDestinationOut);
        UIRectFillUsingBlendMode(rect11, kCGBlendModeDestinationOver);
        UIRectFillUsingBlendMode(rect12, kCGBlendModeDifference);
        UIRectFillUsingBlendMode(rect13, kCGBlendModeExclusion);
        UIRectFillUsingBlendMode(rect14, kCGBlendModeHardLight);
        UIRectFillUsingBlendMode(rect15, kCGBlendModeHue);
        UIRectFillUsingBlendMode(rect16, kCGBlendModeLighten);
        
        UIRectFillUsingBlendMode(rect17, kCGBlendModeLuminosity);
        UIRectFillUsingBlendMode(rect18, kCGBlendModeMultiply);
        UIRectFillUsingBlendMode(rect19, kCGBlendModeNormal);
        UIRectFillUsingBlendMode(rect20, kCGBlendModeOverlay);
        UIRectFillUsingBlendMode(rect21, kCGBlendModePlusDarker);
        UIRectFillUsingBlendMode(rect22, kCGBlendModePlusLighter);
        UIRectFillUsingBlendMode(rect23, kCGBlendModeSaturation);
        UIRectFillUsingBlendMode(rect24, kCGBlendModeScreen);
        UIRectFillUsingBlendMode(rect25, kCGBlendModeSoftLight);
        UIRectFillUsingBlendMode(rect26, kCGBlendModeSourceAtop);
        UIRectFillUsingBlendMode(rect27, kCGBlendModeSourceIn);
        UIRectFillUsingBlendMode(rect28, kCGBlendModeSourceOut);
        UIRectFillUsingBlendMode(rect29, kCGBlendModeXOR);
}

填充模式

有時我們需要按一定的自定義樣式進行填充,這種方式有點類似于貼瓷磚的方式。我們知道如果家里貼地板或瓷磚時,通常我們會先選擇一種瓷磚樣式,根據房間面積我們購買不同量的瓷磚。但是不管買多少,這些瓷磚的樣式都是一模一樣的。填充模式就是為了達到這種效果而產生的:我們只需要繪制一個瓷磚的樣式,然后讓程序自動調用這種樣式填充指定大小的區域。
?Quartz 2D支持兩種填充模式:有顏色填充和無顏色填充。兩種模式使用起來區別很小,有顏色填充就是在繪制瓷磚時就指定顏色,在調用填充時就不用再指定瓷磚顏色;無顏色填充模式就是繪制瓷磚時不用指定任何顏色,在調用填充時再指定具體填充顏色。相比較無顏色填充模式而言,有顏色填充模式更加的靈活。
?如何按指定模式進行圖形填充:
?1、在使用填充模式時首先要構建一個符合CGPatternDrawPatternCallback簽名的方法,這個方法專門用來創建“瓷磚”。注意:如果使用有顏色填充模式,需要設置填充色。
?2、指定一個填充的顏色空間,這個顏色空間跟前面繪制漸變的顏色空間不太一樣,前面創建漸變使用的顏色空間是設備無關的,我們需要基于這個顏色空間創建一個顏色空間專門用于填充(注意對于有顏色填充創建填充顏色空間參數為NULL,不用基于設備無關的顏色空間創建)。
?3、然后我們就可以使用CGPatternCreate方法創建一個填充模式,創建填充模式時需要注意其中的參數)。
?4、最后調用CGContextSetFillPattern方法給圖形上下文指定填充模式(這個時候注意最后一個參數,如果是有顏色填充模式最后一個參數為透明度alpa的地址,對于無顏色填充模式最后一個參數是當前填充顏色空間的顏色數組)。
?5、繪制圖形。
?6、釋放資源。

- (void)drawRect:(CGRect)rect {
    
    CGContextRef context = UIGraphicsGetCurrentContext();
    
//    [self drawBackgroundWithColoredPattern:context];

    [self drawBackgroundWithPattern:context];
}

#pragma mark - 有顏色填充模式
void drawColoredTile(void *info, CGContextRef context){
    //有顏色填充,這里設置填充色
    CGContextSetRGBFillColor(context, 0/255.0, 255.0/255.0, 0/255.0, 1);
    CGContextFillRect(context, CGRectMake(0, 0, 30, 30));
    CGContextFillRect(context, CGRectMake(30, 30, 30, 30));
}

-(void)drawBackgroundWithColoredPattern:(CGContextRef) context{
    //設備無關的顏色空間
//    CGColorSpaceRef rgbSpace = CGColorSpaceCreateDeviceRGB();
    //模式填充顏色空間,注意對于有顏色填充模式,這里傳NULL
    CGColorSpaceRef colorSpace = CGColorSpaceCreatePattern(NULL);
    //將填充色顏色空間設置為模式填充的顏色空間
    CGContextSetFillColorSpace(context, colorSpace);
    
    //填充模式回調函數結構體
    CGPatternCallbacks callback = {0,  &drawColoredTile, NULL};
    /*填充模式
     info://傳遞給callback的參數
     bounds:瓷磚大小
     matrix:形變
     xStep:瓷磚橫向間距
     yStep:瓷磚縱向間距
     tiling:貼磚的方法
     isClored:繪制的瓷磚是否已經指定了顏色(對于有顏色瓷磚此處指定位true)
     callbacks:回調函數
     */
    CGPatternRef pattern = CGPatternCreate(NULL, CGRectMake(0, 0, 2*30, 2*30), CGAffineTransformIdentity, 2*30+5, 2*30+5, kCGPatternTilingNoDistortion, true, &callback);
    
    CGFloat alpha = 1;
    //注意最后一個參數對于有顏色瓷磚指定為透明度的參數地址,對于無顏色瓷磚則指定當前顏色空間對應的顏色數組
    CGContextSetFillPattern(context, pattern, &alpha);
    
    UIRectFill(CGRectMake(0, 0, 320, 568));
    
//    CGColorSpaceRelease(rgbSpace);
    CGColorSpaceRelease(colorSpace);
    CGPatternRelease(pattern);
}


#pragma mark - 無顏色填充模式
//填充瓷磚的回調函數(必須滿足CGPatternCallbacks簽名)
void drawTile(void *info, CGContextRef context){
    CGContextFillRect(context, CGRectMake(0, 0, 30, 30));
    CGContextFillRect(context, CGRectMake(30, 30, 30, 30));
}

-(void)drawBackgroundWithPattern:(CGContextRef)context{
    //設備無關的顏色空間
    CGColorSpaceRef rgbSpace = CGColorSpaceCreateDeviceRGB();
    //模式填充顏色空間
    CGColorSpaceRef colorSpace = CGColorSpaceCreatePattern(rgbSpace);
    //將填充色顏色空間設置為模式填充的顏色空間
    CGContextSetFillColorSpace(context, colorSpace);
    
    //填充模式回調函數結構體
    CGPatternCallbacks callback = {0, &drawTile, NULL};
    /*填充模式
     info://傳遞給callback的參數
     bounds:瓷磚大小
     matrix:形變
     xStep:瓷磚橫向間距
     yStep:瓷磚縱向間距
     tiling:貼磚的方法(瓷磚擺放的方式)
     isClored:繪制的瓷磚是否已經指定了顏色(對于無顏色瓷磚此處指定位false)
     callbacks:回調函數
     */
    CGPatternRef pattern = CGPatternCreate(NULL, CGRectMake(0, 0, 2*30, 2*30), CGAffineTransformIdentity, 2*30+5, 2*30+5, kCGPatternTilingNoDistortion, false, &callback);
    
    CGFloat components[] = {0/255.0, 255.0/255.0, 0/255.0, 1.0};
    //注意最后一個參數對于無顏色填充模式指定為當前顏色空間顏色數據
    CGContextSetFillPattern(context, pattern, components);
    //    CGContextSetStrokePattern(context, pattern, components);
    UIRectFill(CGRectMake(0, 0, 320, 568));
    
    CGColorSpaceRelease(rgbSpace);
    CGColorSpaceRelease(colorSpace);
    CGPatternRelease(pattern);
}


drawTile回調方法中不要使用UIKit封裝方法進行圖形繪制(例如UIRectFill等),由于這個方法由Core Graphics內部調用,而Core Graphics考慮到跨平臺問題,內部是不允許調用UIKit方法的
上下文變換

UIKit開發中UIView有一個transform屬性用于控件的形變,其實在繪圖中我們也經常用到圖形形變,這個時候可以借助圖形上下文的形變方法來完成。在弄清形變之前我們要清楚圖形上下文的坐標原點,因為無論是位移還是旋轉都是相對于坐標原點進行的。Quartz 2D的坐標系同UIKit并不一樣,它的坐標原點在屏幕左下方,但是為了統一編程方式,UIKit對其進行了轉換,坐標原點統一在屏幕左上角。注意在設置圖形上下文形變之前一定要注意保存上下文的初始狀態,在使用完之后進行恢復。否則在處理多個圖形形變的時候很容易弄不清楚到底是基于怎樣的坐標系進行繪圖,容易找不到原點。

- (void)drawRect:(CGRect)rect {
    CGContextRef context = UIGraphicsGetCurrentContext();
    // 保存初始狀態
    CGContextSaveGState(context);
    // 形變:圖形上下文向右平移100
    CGContextTranslateCTM(context, 100, 0);
    // 形變:縮放0.8
    CGContextScaleCTM(context, 0.8, 0.8);
    // 形變:旋轉
    CGContextRotateCTM(context, M_PI_4 / 4);
    // 繪制圖片
    UIImage *image = [UIImage imageNamed:@"image_2.jpg"];
    [image drawInRect:CGRectMake(0, 60, 200, 200)];
    
    // 恢復到初始狀態
    CGContextRestoreGState(context);
}
刷新視圖

在UIView的drawRect:中繪制的圖形會在控件顯示的時候調用(而且顯示時會重繪所有圖形),有時候我們希望繪制內容的顯示是實時的,此時我們就需要調用繪圖方法重新繪制,但是在iOS開發中不允許開發者直接調用drawRect:方法,刷新繪制內容需要調用setNeedsDisplay方法。

// .h文件
#import <UIKit/UIKit.h>

@interface PXShowView : UIView

@property (nonatomic, assign) CGFloat fontSize;

@end

// .m文件
#import "PXShowView.h"

@implementation PXShowView

- (void)drawRect:(CGRect)rect {
    NSString *str = @"你號OC!";
    UIFont *font = [UIFont systemFontOfSize:self.fontSize];
    UIColor *fontColor = [UIColor redColor];
    [str drawInRect:CGRectMake(100, 120, 300, 200) withAttributes:@{NSFontAttributeName:font, NSForegroundColorAttributeName:fontColor}];
    
}
@end

// 控制器.m文件
#import "ViewController.h"
#import "PXShowView.h"

@interface ViewController ()

@property (nonatomic, strong) PXShowView *showView;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.showView = [[PXShowView alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.showView.backgroundColor = [UIColor whiteColor];
    self.showView.fontSize = 12.0;
    [self.view addSubview:self.showView];
    
    UIButton *but1 = [[UIButton alloc] initWithFrame:CGRectMake(0, 20, 30, 30)];
    [but1 setTitle:@"30" forState:UIControlStateNormal];
    [but1 setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
    [but1 addTarget:self action:@selector(reloadShowView:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:but1];
    
    UIButton *but2 = [[UIButton alloc] initWithFrame:CGRectMake(0, 80, 30, 30)];
    [but2 setTitle:@"50" forState:UIControlStateNormal];
    [but2 setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
    [but2 addTarget:self action:@selector(reloadShowView:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:but2];

}

- (void) reloadShowView:(UIButton *) sender {
    self.showView.fontSize = [sender.titleLabel.text floatValue];
    [self.showView setNeedsDisplay];
}

- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}

@end

動態圖1.gif
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,533評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,055評論 3 414
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,365評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,561評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,346評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,889評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,978評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,118評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,637評論 1 333
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,558評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,739評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,246評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,980評論 3 346
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,362評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,619評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,347評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,702評論 2 370

推薦閱讀更多精彩內容