Quartz 2D

weixin_34232744發表於2017-12-18

###Quartz 2D:

  • Quartz 2D是一個二維繪圖引擎,同時支援iOS和Mac OS X系統(跨平臺,純C語言)。包含在Core Graphics框架中。

Quartz 2D能完成的工作:

  • 繪製圖形: 線條/三角形/矩形/圓/弧等
  • 繪製文字
  • 繪製/生成圖片
  • 讀取/生成PDF
  • 自定義UI控制元件
  • ... ...

Quartz 2D繪圖主要步驟:

  • 通過Quartz 2D原生API繪圖:

    • 獲取[圖形上下文]物件
    • 向[圖形上下文]物件中新增[路勁]
    • 渲染(把[圖形上下文]中的圖形繪製到對應的裝置上)

圖形上下文CGContextRef

  • 圖形上下文(Graphics Context): 是一個CGContextRef型別的資料
  • 圖形上下文中主要包含如下資訊:
    • 繪製路徑(各種各樣的圖形)
    • 繪圖狀態(顏色、線寬、樣式、旋轉、縮放、平移、圖片剪裁區域等)
    • 輸出目標(繪製到什麼地方去?UIView、PDF、印表機等)

圖形上下文:

提供了以下幾種圖形上下文:

  • Bitmap Graphics Context --效果畫到圖片上
  • PDF Graphics Context --畫到PDF上
  • Window Graphics Context --畫到Mac電腦視窗上
  • Layer Graphics Context(UI 控制元件) --畫到UI控制元件上
  • Printer Graphics Context --畫到印表機

PS: 相同的一套繪圖序列,指定不同的Graphics Context, 就可以將相同的影像繪製到不同的目標上。

通過UIBezierPath + 圖形上下文繪製圖形:

  • 獲取圖形上下文物件
  • 建立UIBezierPath物件
  • 向UIBezierPath物件中繪製圖形
  • 把UIBezierPath物件新增到上下文中
  • 把上下文物件渲染到裝置上

PS: UIBezierPath物件可以獨立使用,無需手動獲取 圖形上下文 物件,這裡為了更好的理解 圖形上下文物件,採取手動獲取圖形上下文物件的方式來繪圖。

自定義UIView時,實現檔案中:

/*
// Only override drawRect: if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
- (void)drawRect:(CGRect)rect {
    // Drawing code
}
*/
複製程式碼

__即:__在drawRect:方法中才能取得跟view相關聯的圖形上下文 我們才能繪製各種圖形。

drawRect: 方法僅在view第一次顯示在Window上時呼叫一次,如果想重新呼叫 需要手動呼叫setNeedsDisplay或setNeedsDisplayInRect:方法。

不可手動呼叫drawRect: 方法,該方法是由系統在需要呼叫的時候呼叫--不能主動呼叫該方法。

  • Quartz 2D原生API繪製:

    • 繪製直線:
//1.獲取圖形上下文
    CGContextRef ref = UIGraphicsGetCurrentContext();
    
    //2. 繪製各種路徑
    //2.1 設定一個起點
    CGContextMoveToPoint(ref, 20, 100);
    //2.2 設定一個終點
    CGContextAddLineToPoint(ref, 100, 160);
    //3. 渲染
    CGContextStrokePath(ref);
複製程式碼
  • 繪製三角形:
//1.獲取圖形上下文
    CGContextRef ref = UIGraphicsGetCurrentContext();
    
    //2. 繪製各種路徑
    //2.1 設定一個起點
    CGContextMoveToPoint(ref, 20, 100);
    //2.2 設定一個終點
    CGContextAddLineToPoint(ref, 100, 160);
    //2.3 再新增一個終點
    CGContextAddLineToPoint(ref, 150, 100);
    
    //2.4 關閉路徑
    CGContextClosePath(ref);
    
    //3. 渲染
    CGContextStrokePath(ref);
複製程式碼
  • UIBezierPath繪製圖形:
    • 繪製直線:
//1. 獲取圖形上下文
    CGContextRef ref = UIGraphicsGetCurrentContext();
    //2. 建立UIBezierPath物件
    UIBezierPath *path = [UIBezierPath bezierPath];
    //3. 向UIBezierPath新增路徑
    [path moveToPoint:CGPointMake(30, 100)];
    [path addLineToPoint:CGPointMake(300, 300)];
    //4. 把UIBezierPath物件新增到上下文中
    CGContextAddPath(ref, path.CGPath);
    //設定狀態資訊
    //i. 線寬
    CGContextSetLineWidth(ref, 10);
    //ii. 設定線段兩端樣式
    /*
     typedef CF_ENUM(int32_t, CGLineCap) {
     kCGLineCapButt,        //預設
     kCGLineCapRound,
     kCGLineCapSquare
     };
     */
    CGContextSetLineCap(ref, kCGLineCapRound);
    //iii. 設定線段連線處的樣式
    /*
     typedef CF_ENUM(int32_t, CGLineJoin) {
     kCGLineJoinMiter,      //預設
     kCGLineJoinRound,
     kCGLineJoinBevel
     };
     */
    CGContextSetLineJoin(ref, kCGLineJoinRound);
    //iV. 設定繪圖顏色
    //    [[UIColor redColor] setStroke]; //畫邊的時候使用紅色 --僅用於渲染時 為kCGPathStroke時
    //    [[UIColor yellowColor] setFill];    //設定填充時顏色 --kCGPathFill
    [[UIColor blueColor] set];  //填充和描邊 使用同一顏色
    //5. 渲染
    //    CGContextStrokePath(ref);
    //上面所有的設定狀態的程式碼,都會將狀態應用於當前上下文中的所有路徑
    //    CGContextDrawPath(ref, kCGPathStroke);    //與[[UIColor redColor] setStroke];對應
    //    CGContextDrawPath(ref, kCGPathFill);      //與[[UIColor yellowColor] setFill];對應
    CGContextDrawPath(ref, kCGPathFillStroke);  //既填充也描邊    //與[[UIColor blueColor] set];對應
複製程式碼
  • 繪製三角形:
//1. 獲取上下文
    CGContextRef ref = UIGraphicsGetCurrentContext();
    //2. 建立UIBezierPath物件
    UIBezierPath *path = [UIBezierPath bezierPath];
    //3. 向UIBezierPath新增路徑
    [path moveToPoint:CGPointMake(100, 200)];
    [path addLineToPoint:CGPointMake(160, 300)];
    [path addLineToPoint:CGPointMake(220, 200)];
    //關閉路徑
    [path closePath];
    //4. 把UIBezierPath物件新增到上下文中
    CGContextAddPath(ref, path.CGPath); //OC物件 轉 C語言
    //5. 渲染
    //    CGContextStrokePath(ref);
    //or
    /*
     typedef CF_ENUM (int32_t, CGPathDrawingMode) {
     kCGPathFill,
     kCGPathEOFill,
     kCGPathStroke,
     kCGPathFillStroke,
     kCGPathEOFillStroke
     };
     */
    CGContextDrawPath(ref, kCGPathStroke);
複製程式碼
  • 繪製矩形:
//獲取上下文
    CGContextRef ref = UIGraphicsGetCurrentContext();
    //建立UIBezierPath
    //向UIBezierPath中新增路徑
    //繪製矩形
    UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(50, 50, 200, 100)];
    //把UIBezierPath新增到上下文中
    CGContextAddPath(ref, path.CGPath);
    //渲染
    /*
     typedef CF_ENUM (int32_t, CGPathDrawingMode) {
     kCGPathFill,
     kCGPathEOFill,
     kCGPathStroke,
     kCGPathFillStroke,
     kCGPathEOFillStroke
     };
     */
    CGContextDrawPath(ref, kCGPathStroke);
    //    CGContextDrawPath(ref, kCGPathFill); //填充
複製程式碼
  • 繪製橢圓:
//獲取上下文
    CGContextRef ref = UIGraphicsGetCurrentContext();
    //建立UIBezierPath
    //向UIBezierPath中新增路徑
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 200, 100)];
    //把UIBezierPath新增到上下文中
    CGContextAddPath(ref, path.CGPath);
    //渲染
    /*
     typedef CF_ENUM (int32_t, CGPathDrawingMode) {
     kCGPathFill,
     kCGPathEOFill,
     kCGPathStroke,
     kCGPathFillStroke,
     kCGPathEOFillStroke
     };
     */
    CGContextDrawPath(ref, kCGPathStroke);
    //    CGContextDrawPath(ref, kCGPathFill); //填充
複製程式碼
  • 繪製圓形:

    • 第一種方式: 畫橢圓方法 --寬高相等
//獲取上下文
    CGContextRef ref = UIGraphicsGetCurrentContext();
    //建立UIBezierPath
    //向UIBezierPath中新增路徑
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 100, 100)];
    //把UIBezierPath新增到上下文中
    CGContextAddPath(ref, path.CGPath);
    //渲染
    /*
     typedef CF_ENUM (int32_t, CGPathDrawingMode) {
     kCGPathFill,
     kCGPathEOFill,
     kCGPathStroke,
     kCGPathFillStroke,
     kCGPathEOFillStroke
     };
     */
    CGContextDrawPath(ref, kCGPathStroke);
    //    CGContextDrawPath(ref, kCGPathFill); //填充
複製程式碼
- 第二種方式: 繪製矩形 --寬高相等 cornerRadius: 邊長/2.0
複製程式碼
//獲取上下文
    CGContextRef ref = UIGraphicsGetCurrentContext();
    //建立UIBezierPath
    //向UIBezierPath中新增路徑
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50, 50, 100, 100) cornerRadius:50];
    //把UIBezierPath新增到上下文中
    CGContextAddPath(ref, path.CGPath);
    //渲染
    /*
     typedef CF_ENUM (int32_t, CGPathDrawingMode) {
     kCGPathFill,
     kCGPathEOFill,
     kCGPathStroke,
     kCGPathFillStroke,
     kCGPathEOFillStroke
     };
     */
    CGContextDrawPath(ref, kCGPathStroke);
    //    CGContextDrawPath(ref, kCGPathFill); //填充
複製程式碼
- 第三種方式: 繪製圓弧方式畫一個圓
複製程式碼
//獲取上下文
    CGContextRef ref = UIGraphicsGetCurrentContext();
    //建立UIBezierPath
    //向UIBezierPath中新增路徑
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(200, 200) radius:50 startAngle:0 endAngle:M_PI * 2 clockwise:YES];
    //把UIBezierPath新增到上下文中
    CGContextAddPath(ref, path.CGPath);
    //渲染
    /*
     typedef CF_ENUM (int32_t, CGPathDrawingMode) {
     kCGPathFill,
     kCGPathEOFill,
     kCGPathStroke,
     kCGPathFillStroke,
     kCGPathEOFillStroke
     };
     */
    CGContextDrawPath(ref, kCGPathStroke);
    //    CGContextDrawPath(ref, kCGPathFill); //填充
複製程式碼
  • 繪製圓弧:
//獲取上下文
    CGContextRef ref = UIGraphicsGetCurrentContext();
    //建立UIBezierPath
    //向UIBezierPath中新增路徑
    //畫弧
    //ArcCenter: 圓心
    //radius: 半徑
    //startAngle: 開始弧度  --1弧度 = 180度
    //endAngle: 結束弧度
    //繪製一個弧 clockwise: 順時針或逆時針
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(200, 200) radius:50 startAngle:0 endAngle:M_PI_2 clockwise:NO];
    //把UIBezierPath新增到上下文中
    CGContextAddPath(ref, path.CGPath);
    //渲染
    /*
     typedef CF_ENUM (int32_t, CGPathDrawingMode) {
     kCGPathFill,
     kCGPathEOFill,
     kCGPathStroke,
     kCGPathFillStroke,
     kCGPathEOFillStroke
     };
     */
    CGContextDrawPath(ref, kCGPathStroke);
    //    CGContextDrawPath(ref, kCGPathFill); //填充
複製程式碼
  • 繪製圓環:
//獲取上下文
    CGContextRef ref = UIGraphicsGetCurrentContext();
    //建立UIBezierPath
    //向UIBezierPath中新增路徑
    //畫圓環
    //直接畫一個圓 設定線寬 --推薦使用這種方式
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(200, 200) radius:50 startAngle:0 endAngle:M_PI * 2 clockwise:YES];
    CGContextSetLineWidth(ref, 20);   //線寬 裡外各一半
    //把UIBezierPath新增到上下文中
    CGContextAddPath(ref, path.CGPath);
    //渲染
    /*
     typedef CF_ENUM (int32_t, CGPathDrawingMode) {
     kCGPathFill,
     kCGPathEOFill,
     kCGPathStroke,
     kCGPathFillStroke,
     kCGPathEOFillStroke
     };
     */
    CGContextDrawPath(ref, kCGPathStroke);
    //    CGContextDrawPath(ref, kCGPathFill); //填充
複製程式碼

參考資料: 傳智播客教程 iOS-Quartz2D

程式碼

相關文章