CoreGraphics畫圖

在iOS上畫圖主要有3種方法:

  • UIKit, 這是我們最常用的繪圖方法,平時的UIButton、UIImageView就是使用UIkit實現(xiàn)的。
  • Core Graphics, 這是是蘋果提供一套基于C的API框架,使用了Quartz2D作為繪圖引擎。Quartz2D是既可以在iOS上使用,也可以在Mac OS上使用的垮平臺2D繪圖引擎。
  • OpenGL ES, 是種編程規(guī)范,也就是說它只定義了一套規(guī)范,具體的實現(xiàn)由設(shè)備制造商根據(jù)規(guī)范去做。

在上節(jié)UIBezierPath畫一個拱形的tabBar圖形章節(jié)中,我們使用它畫了一個帶拱形的View??梢钥吹経IBezierPath其實就是對Core Graphics的封裝,直接調(diào)用API就可以簡單的畫直線、圓、曲線,省去了對Path的操作細節(jié)。

一. Core Graphics使用簡介

Core Graphics是基于C語言的API,所以它不是面向?qū)ο蟮模谑褂脮r需要一個圖形上下(CGContext)。Context其實就是暫時緩存圖形,等繪制完畢后將圖形返還給所需的對象。

1.1 如何在UIView上使用Graphics繪圖?

使用Core Graphics需要一個畫布(CGContext),而UIView只能在-(void)drawRect:(CGRext)rect方法中獲取當前UIView的相關(guān)聯(lián)的圖形上下文,所以Core Graphics只能在-(void)drawRect:(CGRext)rect方法中使用。

1.2 Core Graphics繪圖七大步驟
  1. 獲取上下文
  1. 設(shè)置畫圖起點
  2. 設(shè)置繪圖類別:直線、圓、圓弧、矩形
  3. 設(shè)置繪圖線條顏色和線條寬度
  4. 開始繪圖
  5. 結(jié)束繪圖
1.3 繪制實例
  • 繪制直線:
-(void)drawRect:(CGRect)rect
{
    // 1. 獲取圖像上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    // 2. 設(shè)置起點
    CGContextMoveToPoint(ctx, 10, 100);
    // 3. 畫直線
    CGContextAddLineToPoint(ctx, 100, 100);
    // 4. 設(shè)置線條顏色 紅色
    CGContextSetRGBStrokeColor(ctx, 1.0, 0, 0, 1.0);
    // 5. 設(shè)置線條寬度
    CGContextSetLineWidth(ctx, 10);
    // 6. 設(shè)置線條的起點和終點的樣式
    CGContextSetLineCap(ctx, kCGLineCapRound);
    // 7. 設(shè)置線條的轉(zhuǎn)角的樣式
    CGContextSetLineJoin(ctx, kCGLineJoinRound);
    // 8. 開始繪制
    CGContextStrokePath(ctx);
}
直線.png
  • 繪制矩形
-(void)drawRect:(CGRect)rect
{
    // 繪制四邊形
    // 1.獲取上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    // 2.繪制四邊形
    CGContextAddRect(ctx, CGRectMake(10, 10, 150, 100));
    [[UIColor colorWithRed:1.0 green:0 blue:0 alpha:1.0] set];
    // 3.渲染圖形到layer上
    // 填充顏色
    CGContextFillPath(ctx);
    // 路徑顏色
    //  CGContextStrokePath(ctx);
}
矩形.png
  • 繪制圓形
-(void)drawRect:(CGRect)rect
{
    // 畫圓弧
    // 1.獲取上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    // 2.畫圓弧
    // x/y 圓心
    // radius 半徑
    // startAngle 開始的弧度
    // endAngle 結(jié)束的弧度
    // clockwise 畫圓弧的方向 (0 順時針, 1 逆時針)
    CGContextAddArc(ctx, 100, 100, 50, 0, M_PI * 2, 1);
//    CGContextClosePath(ctx);
    
    // 3.設(shè)置線條顏色
    [[UIColor redColor] set];
    // 4. 繪圖
         CGContextStrokePath(ctx);
//    CGContextFillPath(ctx);
}
圓形.png

思考:

  1. CGContextStrokePath(ctx); 和 CGContextFillPath(ctx);有啥區(qū)別?
  1. 如何設(shè)置圓形的線條顏色以及實心圓的背景色?

1.4 如何在drawRect方法外繪圖

使用UIGraphicsGetCurrentContext()繪圖有個限制條件就是必須在-(void)drawRect:(CGRect)rect方法中使用,實際應(yīng)用中顯然不夠靈活。那么如何在此方法以外的地方繪制圖形了?常用的有兩種方法:
a. UIGraphicsBeginImageContext(size)繪制位圖
b. 貝塞爾曲線+CAShapeLayer繪圖

  • 使用UIGraphicsBeginImageContext(CGSize size)繪圖
-(void)viewDidLoad 
{
    [super viewDidLoad];
     UIImageView *imgView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    imgView.image = [UIImage imageNamed:@"liuYan.jpeg"];
    imgView.backgroundColor = [UIColor blueColor];
   UIImage *image =  [UIImage imageNamed:@"liuYan.jpeg"];
    NSLog(@"圖片大小%f %f", image.size.width,image.size.height );
    // 我們重新繪圖,將圖片在100x100大小的畫布上繪制
    CGSize size = CGSizeMake(100, 100);
    // 設(shè)置畫圖大小
    UIGraphicsBeginImageContext(CGSizeMake(size.width, size.height));
    [image drawInRect:CGRectMake(0,0,100, 100)];
    UIImage *scaledImage = UIGraphicsGetImageFromCurrentImageContext();
    NSLog(@"修改后大小%f %f", scaledImage.size.width,scaledImage.size.height );
    imgView.image = scaledImage;
    UIGraphicsEndImageContext();
}
liuyan.png

從代碼可以看到我們使用UIGraphicsBeginImageContext(CGSize size)這個方法也可以繪制位圖,而不需要在drawRect方法中繪制。
打印圖片繪制前后大?。?/p>

繪制圖片前后.png

從截圖中可以看到我們將500x600大小的圖片重新繪制后,產(chǎn)生的新圖片scaledImage大小為100x100了。
UIGraphicsBeginImageContext(CGSize size)方法中的CGSize size參數(shù)即圖形上下文中的畫布大小,通過改變這個參數(shù)值,繪制出隨意大小的圖片。
-(void)drawInRect:(CGRect)rect; 方法中的rect參數(shù)告訴畫布我需要在哪個點上畫多大的圖像。例如將 [image drawInRect:CGRectMake(0,0,100, 100)];改為 [image drawInRect:CGRectMake(25,25,50, 50)];


scaleImage.png

圖像跑到了畫布的中間位置,并且圖像大小變成了50x50,但scaledImage仍然是100x100,說明畫布的其他位置并沒有東西填充。

P.S 使用此方法可以將一張圖片進行縮放。

  • 貝塞爾曲線+CAShapeLayer繪圖
-(void)viewDidLoad {
    [super viewDidLoad];
    UIView *rectView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    rectView.backgroundColor = [UIColor redColor];
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:rectView.bounds byRoundingCorners:UIRectCornerTopLeft | UIRectCornerTopRight cornerRadii:CGSizeMake(20,5)];
    CAShapeLayer *layer = [CAShapeLayer layer];
    layer.frame = rectView.bounds;
    layer.path = path.CGPath;
    rectView.layer.mask = layer;
    [self.view addSubview:rectView];
}

部分帶圓角的UIView.png

Core Graphic部分代碼上傳gitHub。

1.5 Core Graphics畫文字和圖片

主要是 darwAtPoint和drawInRect 這兩個方法的使用

// 畫文字
-(void)drawRect:(CGRect)rect {
    // Drawing code
    
    NSString *str = @"Quartz 2D是一個二維繪圖引擎,同時支持iOS和Mac系統(tǒng)";
    
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    //設(shè)置文字大小
    dict[NSFontAttributeName] = [UIFont systemFontOfSize:12];
    //設(shè)置文字顏色
    dict[NSForegroundColorAttributeName] = [UIColor greenColor];
    //設(shè)置描邊寬度
    dict[NSStrokeWidthAttributeName] = @2;
    //設(shè)置描邊顏色
    dict[NSStrokeColorAttributeName] = [UIColor blueColor];
    //設(shè)置陰影
    NSShadow *shadow = [[NSShadow alloc] init];
    //設(shè)置陰影的便宜量
    shadow.shadowOffset = CGSizeMake(1, 1);
    //設(shè)置陰影顏色
    shadow.shadowColor = [UIColor greenColor];
    //設(shè)置陰影模糊程序
    shadow.shadowBlurRadius = 1;
    dict[NSShadowAttributeName] = shadow;
    /**
     AtPoint:文字所畫的位置
     withAttributes:描述文字的屬性.
     */
    //不會自動換行
    [str drawAtPoint:CGPointMake(0,0) withAttributes:dict];
    //會自動換行.
    [str drawInRect:self.bounds withAttributes:dict];
}
// 畫圖片
-(void)drawRect:(CGRect)rect {
    // Drawing code
    //1.加載圖片
    UIImage *image = [UIImage imageNamed:@"liuYan.jpeg"];
    
    //繪制出來的圖片,是保持原來圖片大小
    [image drawAtPoint:CGPointZero];
    //把圖片填充到這個rect當中.
    [image drawInRect:rect];
    //添加裁剪區(qū)域 .把超區(qū)裁剪區(qū)域以外都裁剪掉
//    UIRectClip(CGRectMake(0, 0, 50, 50));
    //平鋪
//    [image drawAsPatternInRect:self.bounds];
    
//    //快速的畫出一個矩形
//    [[UIColor blueColor] set];
//    UIRectFill(CGRectMake(10, 10, 100, 100));
}

二. UIBezierPath使用簡介

UIBezierPath其實是對Core Graphics Path的封裝, 需要與CAShapeLayer配合使用。

2.1 UIBezierPath使用六部曲
  1. 創(chuàng)建貝塞爾曲線
+(instancetype)bezierPath;
  1. 添加子路徑
// 從point開始繪制路徑
-(void)moveToPoint:(CGPoint)point;
  1. 設(shè)置繪圖類別:直線、圓弧、矩形
// 添加一條直線路徑
-(void)addLineToPoint:(CGPoint)point;
// 添加一個圓形路徑
-(void)addArcWithCenter:(CGPoint)center radius:(CGFloat)radius startAngle:(CGFloat)startAngle
// 添加一段圓弧路徑
-(void)addQuadCurveToPoint:(CGPoint)endPoint controlPoint:(CGPoint)controlPoint;
  1. 設(shè)置路徑顏色
 [[UIColor redColor] set];
  1. 開始畫路徑
    [path stroke];
  1. 結(jié)束路徑繪制
-(void)closePath;

主要就以上6個步驟就可以快速的畫出圖形。
注意:如果需要畫一個實心View,可以使用 [[UIColor blackColor] setFill];設(shè)置填充顏色。

2.2 繪制實例
  • 直線
  -(void)drawRect:(CGRect)rect
{
    //1.獲取圖形上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //上下文的狀態(tài)(線的粗細、顏色、鏈接樣式等)
    //設(shè)置線的粗細
    CGContextSetLineWidth(ctx, 10);
    CGContextSetLineJoin(ctx, kCGLineJoinRound);
    CGContextSetLineCap(ctx, kCGLineCapRound);
    //2. 繪制路徑
    UIBezierPath *path = [UIBezierPath bezierPath];
    //2.1 設(shè)置起點
    [path moveToPoint:CGPointMake(50, 250)];
    //2.2 添加一根線到終點
    [path addLineToPoint:CGPointMake(250, 50)];
    
    //畫第二條直線(新起點)
    [path moveToPoint:CGPointMake(100, 250)];
    [path addLineToPoint:CGPointMake(250, 100)];
    
    //把上一條線的終點當做起點來畫第二條線
    [path addLineToPoint:CGPointMake(250, 250)];
    [[UIColor redColor] setStroke];
    //3.把繪制的內(nèi)容添加到上下文中
    // UIBezierPath:UIKit框架   --->   CGPathRef:CoreGraphics框架
    CGContextAddPath(ctx, path.CGPath);
    //4.把上下文的內(nèi)容顯示到view上(渲染到view的layer上)渲染的方式有兩種Stroke(描邊)、Fill(填充)
    CGContextStrokePath(ctx);
}
直線繪制.png
  • 矩形
-(void)drawRect:(CGRect)rect 
{
    //1.獲取圖形上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //設(shè)置顏色
    [[UIColor redColor]set];
    //2.繪制路徑
    //畫矩形
        UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(50, 50, 100, 100)];
    //畫圓角矩形
//    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50, 50, 100, 100) cornerRadius:50];
    //3.把路徑添加到上下文
    CGContextAddPath(ctx, path.CGPath);
    //4.把上下文渲染到view上
    //描邊
    //    CGContextStrokePath(ctx);
    //填充
    CGContextFillPath(ctx);
}
矩形繪制.png

貝塞爾曲線部分代碼上傳到gitHub。

Quartz2D內(nèi)存管理

Quartz2D是C語言的框架,部分地方需要自己管理內(nèi)存:
?使用含有“Create”或“Copy”的函數(shù)創(chuàng)建的對象,使用完后必須釋放,否則將導致內(nèi)存泄露
?使用不含有“Create”或“Copy”的函數(shù)獲取的對象,則不需要釋放
?如果retain了一個對象,不再使用時,需要將其release掉。
可以使用Quartz 2D的函數(shù)來指定retain和release一個對象。例如,如果創(chuàng)建了一個CGColorSpace對象,則使用函數(shù)CGColorSpaceRetain和CGColorSpaceRelease來retain和release對象。也可以使用Core Foundation的CFRetain和CFRelease。注意不能傳遞NULL值給這些函數(shù)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容