參考 :http://www.mgenware.com/blog/?p=493
這三種東西:CGContextRef
,CGPath
和UIBezierPath
。本質上都是一樣的,都是使用Quartz來繪畫。只不過把繪圖操作暴露在不同的API層面上,在具體實現上,當然也會有一些細小的差別。
我們將主要使用這3個類型,繪制出同一張圖片,如下,一個笑臉:
首先使用Quartz的CGPath
來做這張圖。很簡單,首先創建用於轉移坐標的Transform,然后創建一個CGMutablePathRef
(屬於CGPath
類型)對象。接着通過兩個CGPathAddEllipseInRect
和一個CGPathAddArc
函數來繪制Path中的兩個眼睛和一個嘴,注意把CGAffineTransform
的地址傳進去,這樣Transform才會應用。接着把這個創建好的CGPath
加入到當前CGContextRef
中,最后通過CGContextRef
執行繪畫。
代碼:
- (void)viewDidLoad { [super viewDidLoad]; //開始圖像繪圖 UIGraphicsBeginImageContext(self.view.bounds.size); //獲取當前CGContextRef CGContextRef gc = UIGraphicsGetCurrentContext(); //創建用於轉移坐標的Transform,這樣我們不用按照實際顯示做坐標計算 CGAffineTransform transform = CGAffineTransformMakeTranslation(50, 50); //創建CGMutablePathRef CGMutablePathRef path = CGPathCreateMutable(); //左眼 CGPathAddEllipseInRect(path, &transform, CGRectMake(0, 0, 20, 20)); //右眼 CGPathAddEllipseInRect(path, &transform, CGRectMake(80, 0, 20, 20)); //笑 CGPathMoveToPoint(path, &transform, 100, 50); CGPathAddArc(path, &transform, 50, 50, 50, 0, M_PI, NO); //將CGMutablePathRef添加到當前Context內 CGContextAddPath(gc, path); //設置繪圖屬性 [[UIColor blueColor] setStroke]; CGContextSetLineWidth(gc, 2); //執行繪畫 CGContextStrokePath(gc); //從Context中獲取圖像,並顯示在界面上 UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); UIImageView *imgView = [[UIImageView alloc] initWithImage:img]; [self.view addSubview:imgView]; }
接下來,我們不去使用CGPath
類型的相關函數,而完全使用CGContextRef
相關的函數,這些函數執行起來其實是和上面講的的CGPath
完全等價的。
這里需要注意的是,完全使用CGContextRef
的話,Transform的應用需使用CGContextTranslateCTM
函數。
完整代碼:
- (void)viewDidLoad { [super viewDidLoad]; //開始圖像繪圖 UIGraphicsBeginImageContext(self.view.bounds.size); //獲取當前CGContextRef CGContextRef gc = UIGraphicsGetCurrentContext(); //使用CGContextTranslateCTM函數來轉移坐標的Transform,這樣我們不用按照實際顯示做坐標計算 CGContextTranslateCTM(gc, 50, 50); //左眼 CGContextAddEllipseInRect(gc, CGRectMake(0, 0, 20, 20)); //右眼 CGContextAddEllipseInRect(gc, CGRectMake(80, 0, 20, 20)); //笑 CGContextMoveToPoint(gc, 100, 50); CGContextAddArc(gc, 50, 50, 50, 0, M_PI, NO); //設置繪圖屬性 [[UIColor blueColor] setStroke]; CGContextSetLineWidth(gc, 2); //執行繪畫 CGContextStrokePath(gc); //從Context中獲取圖像,並顯示在界面上 UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); UIImageView *imgView = [[UIImageView alloc] initWithImage:img]; [self.view addSubview:imgView]; }
同樣會繪制出上面的圖形。
最后我們使用UIBezierPath
類型來完成上述圖形,UIBezierPath
很有意思,它包裝了Quartz的相關API,自己存在於UIKit
中,因此不是基於C的API,而是基於Objective-C對象的。那么一個非常重要的點是由於離開了Quartz繪圖,所以不需要考慮Y軸翻轉的問題,在畫弧的時候,clockwise
參數是和現實一樣的,如果需要順時針就傳YES
,而不是像Quartz環境下傳NO
的。
其次橢圓的創建需使用bezierPathWithOvalInRect
方法,這里名字是Oral
而不是Quartz中的Ellipse
。
最后注意UIBezierPath
的applyTransform
方法需要最后調用。
完整代碼:
- (void)viewDidLoad { [super viewDidLoad]; //開始圖像繪圖 UIGraphicsBeginImageContext(self.view.bounds.size); //創建UIBezierPath UIBezierPath *path = [UIBezierPath bezierPath]; //左眼 [path appendPath:[UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 20, 20)]]; //右眼 [path appendPath:[UIBezierPath bezierPathWithOvalInRect:CGRectMake(80, 0, 20, 20)]]; //笑 [path moveToPoint:CGPointMake(100, 50)]; //注意這里clockwise參數是YES而不是NO,因為這里不知Quartz,不需要考慮Y軸翻轉的問題 [path addArcWithCenter:CGPointMake(50, 50) radius:50 startAngle:0 endAngle:M_PI clockwise:YES]; //使用applyTransform函數來轉移坐標的Transform,這樣我們不用按照實際顯示做坐標計算 [path applyTransform:CGAffineTransformMakeTranslation(50, 50)]; //設置繪畫屬性 [[UIColor blueColor] setStroke]; [path setLineWidth:2]; //執行繪畫 [path stroke]; //從Context中獲取圖像,並顯示在界面上 UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); UIImageView *imgView = [[UIImageView alloc] initWithImage:img]; [self.view addSubview:imgView]; }