iOS繪圖教程(我的學習總結)

iOS繪圖教程:http://www.cocoachina.com/applenews/devnews/2014/0115/7703.html

 

 本篇博文是爲了梳理學習過程當中得框架,上邊連接是cocoachina的教程,更詳細一些html

 

iOS支持兩套圖形API族:Core Graphics/QuartZ 2D 和OpenGL ES安全

 

 路徑用於描述由一序列線和Bézier曲線構成的2D幾何形狀app

Core Graphics中也有一些用於建立簡單路徑(好比矩形和橢圓形)的便利函數。對於更爲複雜的路徑,必須用Core Graphics框架提供的函數自行建立框架

Bézier曲線是法國數學家「貝塞爾」在工做中發現,任何一條曲線均可以經過與它相切的控制線兩端的點的位置來定義。函數

Bézier曲線學習

wps_clip_image-26605

兩種方法建立弧度 第一種測試

void CGContextAddArc (
  CGContextRef c,    
  CGFloat x,             //圓心的x座標
  CGFloat y,  //圓心的x座標
  CGFloat radius,  //圓的半徑
  CGFloat startAngle,    //開始弧度
  CGFloat endAngle,  //結束弧度
  int clockwise          //0表示順時針,1表示逆時針
);

 

第二種spa

void CGContextAddArcToPoint (
  CGContextRef c,
  CGFloat x1, //端點1的x座標
  CGFloat y1, //端點1的y座標
  CGFloat x2, //端點2的x座標
  CGFloat y2, //端點2的y座標
  CGFloat radius //半徑
);
Curves
畫曲線,通常是一條直線,而後定義幾個控制點,使直線變彎曲。
三次曲線函數
void CGContextAddCurveToPoint (
  CGContextRef c,
  CGFloat cp1x, //控制點1 x座標
  CGFloat cp1y, //控制點1 y座標
  CGFloat cp2x, //控制點2 x座標
  CGFloat cp2y, //控制點2 y座標
  CGFloat x, //直線的終點 x座標
  CGFloat y //直線的終點 y座標
);
二次曲線函數
void CGContextAddQuadCurveToPoint (
  CGContextRef c,
  CGFloat cpx, //控制點 x座標
  CGFloat cpy, //控制點 y座標
  CGFloat x, //直線的終點 x座標
  CGFloat y //直線的終點 y座標
);
Ellipses
void CGContextAddEllipseInRect (
  CGContextRef context,
  CGRect rect //一矩形
);
若是矩形是一個正方形,那麼畫出來就是一個圓
執行完函數貌似current point不會變化,沒有具體測試過
Rectangles
void CGContextAddRect (
  CGContextRef c,
  CGRect rect
);
 
一次性畫出多個矩形
void CGContextAddRects (
  CGContextRef c,
  const CGRect rects[],
  size_t count
);
須要注意的是,畫矩形有一些特別,current point沒有發生變化
 
Creating a Path
調用函數 CGContextBeginPath 開始建立路徑,線調用函數CGContextMoveToPoint設置起點
而後開始畫本身想畫的路徑,注意一下幾點:
1.Lines, arcs, and curves,是從current point開始的
2.假如想封閉一條路徑,那麼調用函數 CGContextClosePath 把當前點和起點鏈接起來
3.當在畫 arcs的時候,Quartz會畫一條線從current point 到 starting point
4.畫矩形的時候不會有第三條那這樣的的一條直線
5.建立完路徑後,必須調用 painting 函數  fill or stroke the path,否則不會畫上面東東在相應的設備上】
6.開始建立一個新的路徑的時候,使用函數 CGContextBeginPath。
 
重複利用路徑的相關函數和數據類型
 
 
們有了兩大繪圖框架的支持以及三種得到圖形上下文的方法(drawRect:、drawRect: inContext:、UIGraphicsBeginImageContextWithOptions)。那麼咱們就有6種繪圖的形式。若是你有些困惑了,不用怕,我接下來將說明這6種狀況。無需擔憂尚未具體的繪圖命令,你只需關注上下文如何被建立以及咱們是在使用UIKit仍是Core Graphics。
 
第一種繪圖形式:在UIView的子類方法drawRect:中繪製一個藍色圓,使用UIKit在Cocoa爲咱們提供的當前上下文中完成繪圖任務。
  1. - (void) drawRect: (CGRect) rect { 
  2.  
  3. UIBezierPath* p = [UIBezierPathbezierPathWithOvalInRect:CGRectMake(0,0,100,100)]; 
  4.  
  5. [[UIColor blueColor] setFill]; 
  6.  
  7. [p fill]; 
  8.  

第二種繪圖形式:使用Core Graphics實現繪製藍色圓。線程

  1. - (void) drawRect: (CGRect) rect { 
  2.  
  3. CGContextRef con = UIGraphicsGetCurrentContext(); 
  4.  
  5. CGContextAddEllipseInRect(con, CGRectMake(0,0,100,100)); 
  6.  
  7. CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor); 
  8.  
  9. CGContextFillPath(con); 
  10.  

上邊兩種方法對比  第一種是使用UIBezierPath  這個方法  自動的在當前view中畫出圖形代理

第二種方法  是使用core Graphics  是得到上下文以後進行繪圖  CGContextRef

 

第三種繪圖形式:我將在UIView子類的drawLayer:inContext:方法中實現繪圖任務。drawLayer:inContext:方法是一個繪製圖層內容的代理方法。爲了可以調用drawLayer:inContext:方法,咱們須要設定圖層的代理對象。但要注意,不該該將UIView對象設置爲顯示層的委託對象,這是由於UIView對象已是隱式層的代理對象,再將它設置爲另外一個層的委託對象就會出問題。輕量級的作法是:編寫負責繪圖形的代理類。在MyView.h文件中聲明以下代碼:

  1. @interface MyLayerDelegate : NSObject 
  2.  
  3. @end 

而後MyView.m文件中實現接口代碼:

  1. @implementation MyLayerDelegate 
  2.  
  3. - (void)drawLayer:(CALayer*)layer inContext:(CGContextRef)ctx { 
  4.  
  5.   UIGraphicsPushContext(ctx); 
  6.  
  7.   UIBezierPath* p = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0,0,100,100)]; 
  8.  
  9.   [[UIColor blueColor] setFill]; 
  10.  
  11.   [p fill]; 
  12.  
  13.   UIGraphicsPopContext(); 
  14.  
  15.  
  16. @end 

 

直接將代理類的實現代碼放在MyView.m文件的#import代碼的下面,這樣感受好像在使用私有類完成繪圖任務(雖然這不是私有類)。須要注意的是,咱們所引用的上下文並非當前上下文,因此爲了可以使用UIKit,咱們須要將引用的上下文轉變成當前上下文。
 
由於圖層的代理是assign內存管理策略,那麼這裏就不能以局部變量的形式建立MyLayerDelegate實例對象賦值給圖層代理。這裏選擇在MyView.m中增長一個實例變量,由於實例變量默認是strong:
 
  1. @interface MyView () { 
  2.  
  3. MyLayerDelegate* _layerDeleagete; 
  4.  
  5.  
  6. @end 
使用該圖層代理:
 
  1. MyView *myView = [[MyView alloc] initWithFrame: CGRectMake(0, 0, 320, 480)]; 
  2.  
  3. CALayer *myLayer = [CALayer layer]; 
  4.  
  5. _layerDelegate = [[MyLayerDelegate alloc] init]; 
  6.  
  7. myLayer.delegate = _layerDelegate; 
  8.  
  9. [myView.layer addSublayer:myLayer]; 
  10.  
  11. [myView setNeedsDisplay]; // 調用此方法,drawLayer: inContext:方法纔會被調用。 
第四種繪圖形式: 使用Core Graphics在drawLayer:inContext:方法中實現一樣操做,代碼以下:
 
  1. - (void)drawLayer:(CALayer*)lay inContext:(CGContextRef)con { 
  2.  
  3. CGContextAddEllipseInRect(con, CGRectMake(0,0,100,100)); 
  4.  
  5. CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor); 
  6.  
  7. CGContextFillPath(con); 
  8.  
最後,演示UIGraphicsBeginImageContextWithOptions的用法,並從上下文中生成一個UIImage對象。生成UIImage對象的代碼並不須要等待某些方法被調用後或在UIView的子類中才能去作。
 
第五種繪圖形式: 使用UIKit實現:
 
  1. UIGraphicsBeginImageContextWithOptions(CGSizeMake(100,100), NO, 0); 
  2.  
  3. UIBezierPath* p = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0,0,100,100)]; 
  4.  
  5. [[UIColor blueColor] setFill]; 
  6.  
  7. [p fill]; 
  8.  
  9. UIImage* im = UIGraphicsGetImageFromCurrentImageContext(); 
  10.  
  11. UIGraphicsEndImageContext(); 

解釋一下UIGraphicsBeginImageContextWithOptions函數參數的含義:第一個參數表示所要建立的圖片的尺寸;第二個參數用來指定所生成圖片的背景是否爲不透明,如上咱們使用YES而不是NO,則咱們獲得的圖片背景將會是黑色,顯然這不是我想要的;第三個參數指定生成圖片的縮放因子,這個縮放因子與UIImage的scale屬性所指的含義是一致的。傳入0則表示讓圖片的縮放因子根據屏幕的分辨率而變化,因此咱們獲得的圖片不論是在單分辨率仍是視網膜屏上看起來都會很好。

 

第六種繪圖形式: 使用Core Graphics實現:
 
  1. UIGraphicsBeginImageContextWithOptions(CGSizeMake(100,100), NO, 0); 
  2.  
  3. CGContextRef con = UIGraphicsGetCurrentContext(); 
  4.  
  5. CGContextAddEllipseInRect(con, CGRectMake(0,0,100,100)); 
  6.  
  7. CGContextSetFillColorWithColor(con, [UIColor blueColor].CGColor); 
  8.  
  9. CGContextFillPath(con); 
  10.  
  11. UIImage* im = UIGraphicsGetImageFromCurrentImageContext(); 
  12.  
  13. UIGraphicsEndImageContext(); 
 
 UIKit和Core Graphics能夠在相同的圖形上下文中混合使用。在iOS 4.0以前,使用UIKit和UIGraphicsGetCurrentContext被認爲是線程不安全的。而在iOS4.0之後蘋果讓繪圖操做在第二個線程中執行解決了此問題。
 
以後就不寫了~能夠看下原文
相關文章
相關標籤/搜索