quartz2d(一)

轉(zhuǎn)載自:http://m.2cto.com/kf/201612/572489.html

?

UIKIt UIBezierPath Core Graphics OpenGL ES Quartz2D的區(qū)別和聯(lián)系

UIKIt:UIKit中的控件都是基于Core Graphics實現(xiàn)的

UIBezierPath:UIBezierPath屬于UIKit,它是蘋果對復(fù)雜的Core Graphics進(jìn)行的封裝,方便我們用OC語言進(jìn)行簡單的繪圖

Core Graphics:是一套基于C語言的API,支持向量圖形,線、形狀、圖案、路徑、剃度、位圖圖像和pdf 內(nèi)容的繪制。

OpenGL ES:OpenGL是由SGI公司開發(fā)的一套3D圖形軟件接口標(biāo)準(zhǔn),它只是一個標(biāo)準(zhǔn),具體實現(xiàn)由機械制造商來完成,所以不同的機器他的效果可能是完全不一樣的。OpenGL-ES版本,主要是應(yīng)對嵌入式環(huán)境和應(yīng)用的要求,應(yīng)該說在高效完成2D/3D界面的同時,達(dá)到了降低功耗的效果。

Quartz2D:quartz是一個通用的術(shù)語,用于描述在IOS整個媒體層用到的多種技術(shù) 包括圖形、動畫、音頻、適配。Quart 2D 是一組二位繪圖和渲染API,Core Graphic會使用到這組API

Core Graphics框架

繪圖我們要用到Core Graphics框架,Core Graphics Framework是一套基于C的API框架,使用了Quartz作為繪圖引擎。該框架可以用于基于路徑的繪圖、變換、顏色管理、脫屏渲染,模板、漸變、遮蔽、圖像數(shù)據(jù)管理、圖像的創(chuàng)建、遮罩以及PDF文檔的創(chuàng)建、顯示和分析。

Core Graphics API所有的操作都在一個上下文中進(jìn)行。所以在繪圖之前需要獲取該上下文并傳入執(zhí)行渲染的函數(shù)中。介紹兩種最為常用的獲取方法。

第一種方法就是創(chuàng)建一個圖片類型的上下文。調(diào)用UIGraphicsBeginImageContextWithOptions函數(shù)就可獲得用來處理圖片的圖形上下文。利用該上下文,你就可以在其上進(jìn)行繪圖,并生成圖片。調(diào)用UIGraphicsGetImageFromCurrentImageContext函數(shù)可從當(dāng)前上下文中獲取一個UIImage對象。記住在你所有的繪圖操作后別忘了調(diào)用UIGraphicsEndImageContext函數(shù)關(guān)閉圖形上下文。

第二種方法是利用cocoa為你生成的圖形上下文。當(dāng)你子類化了一個UIView并實現(xiàn)了自己的drawRect:方法后,一旦drawRect:方法被調(diào)用,Cocoa就會為你創(chuàng)建一個圖形上下文,此時你對圖形上下文的所有繪圖操作都會顯示在UIView上。

什么是Quartz2D繪圖引擎

Quartz 2D是?個二維繪圖引擎,iOS中?部分控件的內(nèi)容都是通過Quartz 2D畫出來的。 Quartz 2D是純C語言的 Quartz 2D的API來自于CoreGraphics框架 數(shù)據(jù)類型和函數(shù)基本都是CG作為前綴
CGContextRef CGPathRef CGContextStrokePath(ctx)

Quartz 2D能完成的工作

繪制圖形 : 線條\三角形\矩形\圓\弧形 繪制文字 繪制\生成圖片(圖像) 讀取\生成PDF 截圖\裁剪圖片 自定義UI控件

Quartz2D繪圖有以下兩種方式

注意: UIBezierPath 對象可以獨立使用, 無需手動獲取“圖形上下文”對象,此處為了更好的理解“圖形上下文對象”所以暫時還是采用手動獲取“圖形上下文”對象的方式來繪圖。<?喎?"http://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxoMiBpZD0="drawrect方法的使用">drawRect:方法的使用View內(nèi)部有個layer(圖層)屬性,drawRect:方法中取得的是一個Layer Graphics Context,因此,繪制的東西其實是繪制到view的layer上去了 iOS的繪圖操作是在UIView類的drawRect方法中完成的,重寫drawRect方法,在這里進(jìn)行繪圖操作,程序會自動調(diào)用此方法進(jìn)行繪圖。 重繪操作仍然在drawRect方法中完成,蘋果要求我們調(diào)用UIView類中的setNeedsDisplay方法,則程序會自動調(diào)用drawRect方法進(jìn)行重繪。(調(diào)用setNeedsDisplay會自動調(diào)用drawRect)。 在UIView中,重寫drawRect: (CGRect) aRect方法,可以自己定義想要畫的圖案.且此方法一般情況下只會畫一次.也就是說這個drawRect方法一般情況下只會被掉用一次. 當(dāng)某些情況下想要手動重畫這個View,只需要掉用[self setNeedsDisplay]方法即可. rect指的就是當(dāng)前view的bounds,即當(dāng)前視圖的所有范圍。 drawRect:方法是系統(tǒng)幫我們調(diào)用的,不能手動去調(diào)用這個方法。原因是手動去調(diào)用drawRect方法的時候無法保證系統(tǒng)已經(jīng)幫我們創(chuàng)建好了”圖形上下文”,所以這樣就無法保證在drawRect:方法中獲取”圖形上下文”對象,也就無法進(jìn)行繪圖了。 當(dāng)這個view第一次顯示的時候會調(diào)用一次drawRect方法;
當(dāng)這個view執(zhí)行重繪操作的時候會重新調(diào)用drawRect方法;
通過調(diào)用[self setNeedsDisplay] 【重繪整個view】或[self setNeedsDisplayInRect:]【重繪指定區(qū)域】的方式讓view執(zhí)行drawRect方法進(jìn)行重繪。

圖形上下文CGContextRef

圖形上下文的本質(zhì):是一個Quartz2D的繪圖環(huán)境!

幾種不同的渲染方式



c語言的api繪制基本圖形">通過C語言的API繪制基本圖形

#pragma mark - 通過C語言的API繪制基本圖形
- (void)drawRect:(CGRect)rect {

    // 1.獲取上下文
    CGContextRef cxtRef = UIGraphicsGetCurrentContext();
    // 2.設(shè)置起點
    CGContextMoveToPoint(cxtRef, 50, 50);
    // 3.添加線
    CGContextAddLineToPoint(cxtRef, 150, 150);
    // 3.2 繼續(xù)加線段
    CGContextAddLineToPoint(cxtRef, 250, 50);

    // 3.3 向下的線
    // 注意:如果想要新開線,需要重新設(shè)置起點! 
    CGContextMoveToPoint(cxtRef, 150, 150);
    CGContextAddLineToPoint(cxtRef, 150, 250);

    // 4.渲染
//    kCGPathFill 將線段包含的部分渲染成黑色!
//    kCGPathStroke 只負(fù)責(zé)繪制線條!
    CGContextDrawPath(cxtRef, kCGPathStroke);
}

UIBezierPath進(jìn)行直線圖形繪制

#pragma mark - 通過UIBezierPath進(jìn)行圖形繪制
// 不用寫關(guān)于圖形上下文的代碼,已經(jīng)封裝了,但是本質(zhì),還是需要獲取到view相關(guān)的圖形上下文,進(jìn)行繪制!
- (void)drawRect:(CGRect)rect {

    // 1.獲取圖形上下文
//    CGContextRef cxtRef = UIGraphicsGetCurrentContext();

    // 2.創(chuàng)建路徑
    UIBezierPath *path = [UIBezierPath bezierPath];
    // 3.1 設(shè)置起點
    [path moveToPoint:CGPointMake(50, 50)];
    // 3.2 添加線
    [path addLineToPoint:CGPointMake(150, 150)];
    [path addLineToPoint:CGPointMake(250, 50)];

    // 4.渲染--不寫圖形上下文的代碼時,直接使用此方法渲染繪制
    [path stroke];

    // 4.將路徑對象添加到圖形上下文
//    CGContextAddPath(cxtRef, path.CGPath);
    // 5.渲染
//    CGContextDrawPath(cxtRef, kCGPathStroke);
}

UIBezierPath繪制矩形

// MARK: - 1.矩形
- (void)drawRect:(CGRect)rect {
    // 1.獲取圖形上下文
//    CGContextRef cxtRef = UIGraphicsGetCurrentContext();

    // 2.創(chuàng)建矩形的路徑
    UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(50, 50, 200, 80)];
    // 3.渲染
    [path stroke];

    // 3.添加路徑到圖形上下文
//    CGContextAddPath(cxtRef, path.CGPath);
    // 4.渲染
//    CGContextDrawPath(cxtRef, kCGPathStroke);
}

UIBezierPath繪制圓角矩形

// MARK: - 2.圓角矩形
- (void)drawRect:(CGRect)rect {
//    // 1.獲取圖形上下文
//    CGContextRef cxtRef = UIGraphicsGetCurrentContext();

    // 2.創(chuàng)建路徑
    CGFloat radius = 20;
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50, 50, 200, 80) cornerRadius:radius];
    // 3.渲染
    [path stroke];

//    // 3.添加路徑
//    CGContextAddPath(cxtRef, path.CGPath);
//    // 4.渲染
//    CGContextDrawPath(cxtRef, kCGPathStroke);
}

UIBezierPath繪制橢圓

//    // 1.獲取圖形上下文
//    CGContextRef cxtRef = UIGraphicsGetCurrentContext();

    // 2.創(chuàng)建橢圓的路徑
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 200, 80)];
    // 3.渲染
    [path stroke];

//    // 3.添加
//    CGContextAddPath(cxtRef, path.CGPath);
//    // 4.渲染
//    CGContextDrawPath(cxtRef, kCGPathStroke);

UIBezierPath繪制弧形

- (void)drawRect:(CGRect)rect {

    // MARK: - 4.弧形
//    // 1.獲取上下文
//    CGContextRef cxtRef = UIGraphicsGetCurrentContext();

    // 2.圓弧路徑
    /**
     center 圓心
     radius 半徑
     startAngle 起始角度
     endAngle 結(jié)束角度
     clockwise 是否為順時針!
     */
    // 圓心
    CGPoint center = CGPointMake(150, 150);
    // 半徑
    CGFloat radius = 100;
    // 起始角度
    CGFloat startA = 0;
    // 結(jié)束角度
    CGFloat endA = M_PI_2;

    // 是否為順時針
    BOOL clockwise = NO;

    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:clockwise];

    // 3.渲染
    [path stroke];

//    // 3.添加路徑
//    CGContextAddPath(cxtRef, path.CGPath);
//    // 4.渲染
//    CGContextDrawPath(cxtRef, kCGPathStroke);
}

UIBezierPath繪制圓形

// 2.圓路徑
    /**
     center 圓心
     radius 半徑
     startAngle 起始角度
     endAngle 結(jié)束角度
     clockwise 是否為順時針!
     */
    // 圓心
    CGPoint center = CGPointMake(150, 150);
    // 半徑
    CGFloat radius = 100;
    // 起始角度
    CGFloat startA = 0;
    // 結(jié)束角度
    CGFloat endA = M_PI * 2;

    // 是否為順時針
    BOOL clockwise = NO;

    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:clockwise];

    // 渲染
    [path stroke];

UIBezierPath繪制扇形

// 2.圓弧路徑
    /**
     center 圓心
     radius 半徑
     startAngle 起始角度
     endAngle 結(jié)束角度
     clockwise 是否為順時針!
     */
    // 圓心
    CGPoint center = CGPointMake(150, 150);
    // 半徑
    CGFloat radius = 100;
    // 起始角度
    CGFloat startA = 0;
    // 結(jié)束角度
    CGFloat endA = M_PI_4;

    // 是否為順時針
    BOOL clockwise = YES;

    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:clockwise];

    // 2.2 向圓心添加線
    [path addLineToPoint:center];

    // 渲染
    [path fill];

繪圖狀態(tài)信息設(shè)置

1> 設(shè)置線寬 CGContextSetLineWidth
2> 設(shè)置線頭樣式 CGContextSetLineCap
3> 設(shè)置線段接頭樣式 CGContextSetLineJoin
4> 顏色的設(shè)置 [[UIColor redColor] set]

- (void)drawRect:(CGRect)rect {

    //    // 1.獲取圖形上下文
    CGContextRef cxtRef = UIGraphicsGetCurrentContext();

    // 2.創(chuàng)建矩形的路徑
    UIBezierPath *path = [UIBezierPath bezierPath];

    [path moveToPoint:CGPointMake(50, 50)];
    // 第一根線
    [path addLineToPoint:CGPointMake(150, 150)];
    // 第二根線
    [path addLineToPoint:CGPointMake(250, 50)];

    // 3.添加路徑到圖形上下文
    CGContextAddPath(cxtRef, path.CGPath);

    // 3.1 設(shè)置線寬!
    CGContextSetLineWidth(cxtRef, 20);
    // 3.2 設(shè)置線頭樣式
    /**
     kCGLineCapButt,   比較難看的!
     kCGLineCapRound,  圓角
     kCGLineCapSquare  平角
     */
    CGContextSetLineCap(cxtRef, kCGLineCapButt);

    // 3.3 設(shè)置接頭的樣式
    /**
     kCGLineJoinMiter,  尖頭
     kCGLineJoinRound,  圓角
     kCGLineJoinBevel   多余的部分感覺被切了!
     */
    CGContextSetLineJoin(cxtRef, kCGLineJoinMiter);

    // 3.4 顏色的設(shè)置
    [[UIColor redColor] setStroke];
    [[UIColor yellowColor] setFill];

    // 4.渲染
    CGContextDrawPath(cxtRef, kCGPathFillStroke);
}

兩種填充原則

- (void)drawRect:(CGRect)rect {

#pragma mark - 非零繞數(shù)填充規(guī)則
    [self nonzeroWindingNumberRule];

#pragma mark - 奇偶填充規(guī)則
    [self evenOddRule];
}

#pragma mark - 非零繞數(shù)填充規(guī)則
    /**
     * 非零繞數(shù)填充規(guī)則:
     *      在圖形上下文中的任何一個點
     *      被順時針覆蓋標(biāo)記為 1
     *      被逆時針覆蓋標(biāo)記為 -1
     *      當(dāng)標(biāo)記為0的時候不填充,其他則填充
     * 這個規(guī)則與方向有關(guān),與次數(shù)無關(guān)
     */
- (void)nonzeroWindingNumberRule {

    // 1.獲取圖形上下文
    CGContextRef cxtRef = UIGraphicsGetCurrentContext();

    // 2.繪制順時針的圓形
    UIBezierPath *arcY = [UIBezierPath bezierPathWithArcCenter:CGPointMake(150, 150) radius:100 startAngle:0 endAngle:M_PI * 2 clockwise:YES];

    // 3.繪制逆時針的圓形
    UIBezierPath *arcN = [UIBezierPath bezierPathWithArcCenter:CGPointMake(150, 150) radius:75 startAngle:0 endAngle:M_PI * 2 clockwise:NO];

    // 驗證與次數(shù)無關(guān)
    UIBezierPath *arc3 = [UIBezierPath bezierPathWithArcCenter:CGPointMake(150, 230) radius:50 startAngle:0 endAngle:M_PI * 2 clockwise:NO];

    // 4.添加路徑對象
    CGContextAddPath(cxtRef, arcY.CGPath);
    CGContextAddPath(cxtRef, arcN.CGPath);
    CGContextAddPath(cxtRef, arc3.CGPath);

    [[UIColor yellowColor] setFill];

    // 5.渲染
    CGContextDrawPath(cxtRef, kCGPathFill);

}

#pragma mark - 奇偶填充規(guī)則
// even:偶數(shù)  odd:偶數(shù)
/**
 * 奇偶填充規(guī)則解釋:
 *      在圖形上下文中的任何一個點
 *      如果它被路徑對象覆蓋了奇數(shù)次,在進(jìn)行渲染操作的時候這個點就會被渲染
 *      如果它被路徑對象覆蓋了偶數(shù)次,在進(jìn)行渲染操作的時候這個點就不會被渲染
 */
- (void)evenOddRule {

    // 獲取圖形上下文
    CGContextRef cxtRef = UIGraphicsGetCurrentContext();

    // 繪制水平方向矩形
    UIBezierPath *rectH = [UIBezierPath bezierPathWithRect:CGRectMake(50, 100, 200, 100)];

    // 繪制圓形
    UIBezierPath *arcPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(150, 150) radius:75 startAngle:0 endAngle:M_PI * 2 clockwise:YES];

    // 繪制豎直方向的矩形
    UIBezierPath *rectV = [UIBezierPath bezierPathWithRect:CGRectMake(180, 25, 50, 250)];

    // 將路徑對象添加到圖形上下文中
    CGContextAddPath(cxtRef, rectH.CGPath);
    CGContextAddPath(cxtRef, arcPath.CGPath);
    CGContextAddPath(cxtRef, rectV.CGPath);

    [[UIColor orangeColor] setFill];

    // 同時顯示stroke和fill的顏色
    CGContextDrawPath(cxtRef, kCGPathEOFill);
}

模擬下載進(jìn)度條

思路:
在控制器中將 slider 的值傳遞給自定義 view
在自定義 View中,根據(jù)傳遞過來的值繪制弧。
創(chuàng)建一個與自定義 view 一樣大小的 label 來顯示下載進(jìn)度

#import 

@interface DownloadView : UIView
/**
 *  接收滑塊的值
 */
@property (nonatomic, assign) float sliderValue;
@end
#import "DownloadView.h"

@interface DownloadView ()

// 需要先寫,再拖線!
/**
 *  顯示百分比的label
 */
@property (nonatomic, weak) IBOutlet UILabel *valueLbl;

@end

@implementation DownloadView

#pragma mark - 重寫set方法,執(zhí)行重繪操作
- (void)setSliderValue:(float)sliderValue {
    _sliderValue = sliderValue;
    // 內(nèi)部執(zhí)行重繪操作
    [self setNeedsDisplay];
    self.valueLbl.text = [NSString stringWithFormat:@"%.2f%%", (sliderValue * 100)];
}

#pragma mark - 繪制下載進(jìn)度條
- (void)drawRect:(CGRect)rect {
    // 1.獲取上下文
    CGContextRef cxtRef = UIGraphicsGetCurrentContext();
    // 2.創(chuàng)建路徑
    CGFloat startA = -M_PI_2;
    CGFloat endA = self.sliderValue * M_PI * 2 - M_PI_2;

    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(150, 150) radius:150 startAngle:startA endAngle:endA clockwise:YES];

    // 保證繪制出來是扇形
    [path addLineToPoint:CGPointMake(150, 150)];
    // 3.添加路徑
    CGContextAddPath(cxtRef, path.CGPath);
    // 4.渲染
    CGContextDrawPath(cxtRef, kCGPathFill);
}

@end
#import "ViewController.h"
#import "DownloadView.h"

@interface ViewController ()

/**
 *  下載進(jìn)度的視圖
 */
@property (nonatomic, weak) IBOutlet DownloadView *downloadView;

@end

@implementation ViewController

#pragma mark - 滑動事件
- (IBAction)sliderValueChanged:(UISlider *)sender {
    NSLog(@"現(xiàn)在的值是 %f", sender.value);
    // 傳遞值給自定義view
    self.downloadView.sliderValue = sender.value;
}

@end

餅狀圖

思路:
構(gòu)建數(shù)據(jù),NSArray *data = @[@30, @15, @5, @17, @3, @10, @20];。
根據(jù)數(shù)據(jù)個數(shù)繪制“扇形”(?。?br>注意:
每個弧的起始、結(jié)束弧度都是不一樣的
每次繪制完畢一個弧以后都要重新設(shè)置下一次的起始弧度為當(dāng)前的結(jié)束弧度
本次繪制的結(jié)束弧度,為起始弧度+本次的弧度

- (void)drawRect:(CGRect)rect {

    // 1.數(shù)據(jù)
    NSArray *data = @[@30, @15, @5, @17, @3, @10, @20];

    // 1.2 獲取圖形上下文
    CGContextRef cxtRef = UIGraphicsGetCurrentContext();

    // 2.遍歷
    // 2.0.1 圓心,半徑
    CGPoint center = CGPointMake(150, 150);
    CGFloat radius = 120;
    BOOL clockwise = YES;

    // 2.0.2 定義起始角度的變量
    CGFloat startA = 0;

    for (NSInteger i = 0; i < data.count; i++) {

        // 2.1 取出數(shù)據(jù),并轉(zhuǎn)為int類型
        float number = [data[i] floatValue];

        // 2.2 計算所占用的角度
        CGFloat AngleOfNum = number / 100 * (M_PI * 2);

        // 2.3 計算結(jié)束角度
        CGFloat endA = startA + AngleOfNum;

        // 2.4 創(chuàng)建路徑對象
        UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:clockwise];

        // 2.4.2 添加線
        [path addLineToPoint:center];

        // 2.5 添加路徑
        CGContextAddPath(cxtRef, path.CGPath);

        // 隨機色
        [[UIColor colorWithRed:((float)arc4random_uniform(256) / 255.0) green:((float)arc4random_uniform(256) / 255.0) blue:((float)arc4random_uniform(256) / 255.0) alpha:1.0] setFill];

        // 2.6 渲染
        CGContextDrawPath(cxtRef, kCGPathFill);

        // 2.7 改變角度
        startA = endA;
    }
}

最后編輯于
?著作權(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)容