Quartz2D學(xué)習(xí)筆記

Quartz2D

Quartz2D是一個二維繪圖引擎,iOS和Mac都支持

我們可以用來:

  • 繪制圖形
  • 繪制文字
  • 繪制、生成圖片(圓形頭像)
  • 讀取仔拟、生成PDF
  • 截圖姆泻、裁剪圖片(常用)
  • 自定義UI控件(常用)
  • 手勢解鎖

基本圖形繪制

圖形上下文(CGContextRef)

保存繪圖信息咒唆、繪圖狀態(tài)

決定繪制的輸出目標(biāo)(Bitmap、PDF了讨、Window捻激、Layer、Printer)

自定義view步驟
  1. 實(shí)現(xiàn)drawRect方法
  2. 取得當(dāng)前view相關(guān)聯(lián)的圖形上下文
  3. 繪制相應(yīng)的圖形內(nèi)容
  4. 利用圖形上下文將繪制的所有內(nèi)容渲染顯示到view上面

繪制圖形的原理是這樣的 這里是面對C語言的 不是面向?qū)ο罅?br> Ref表示引用

// 只有在drawRect才能獲取圖形上下文(上面5種中的layer)
- (void)drawRect:(CGRect)rect {
    // 1.獲取圖形上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    // 2.描述路徑(路徑 create )
    CGMutablePathRef path = CGPathCreateMutable();
    // path:給哪個路徑設(shè)置起點(diǎn)
    CGPathMoveToPoint(path, NULL, 50, 50);
    // 添加一個線到某個點(diǎn)
    CGPathAddLineToPoint(path, NULL, 200, 200);
    // 3.把路徑添加到上下文
    CGContextAddPath(ctx, path);
    // 4.渲染上下文(Bitmap,PDF 等)
    CGContextStrokePath(ctx);
    
}

其實(shí)可以用我們比較熟悉面向?qū)ο蟮姆绞?比如貝塞爾曲線

- (void)drawRect:(CGRect)rect {
    UIBezierPath *path = [UIBezierPath bezierPath];
    
    [path moveToPoint:CGPointMake(50, 50)];
    
    [path addLineToPoint:CGPointMake(200, 200)];
    // path.lineWidth
    // path.lineCapStyle
    // path.lineJoinStyle
    [path stroke];//stroke是描邊
}

補(bǔ)充1: 下面這種不好的地方在于 好幾條線都是一個path 不好管理

- (void)drawRect:(CGRect)rect {
    // 1.獲取圖形上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    // 2.描述路徑(直接控制上下文)
    CGContextMoveToPoint(ctx, 50, 50);
    CGContextAddLineToPoint(ctx, 100, 50);
    // 默認(rèn)起點(diǎn)是從上一個線的終點(diǎn) (如果不想連在一起 就在MoveToPoint)
    CGContextAddLineToPoint(ctx, 100, 200);
    // 顏色
    [[UIColor greenColor] setStroke];
    // 線寬
    CGContextSetLineWidth(ctx, 10);
    // 設(shè)置連接樣式
    CGContextSetLineJoin(ctx, kCGLineJoinRound);
    // 設(shè)置頂角樣式
    CGContextSetLineCap(ctx, kCGLineCapRound);
    // 4.渲染上下文(Bitmap,PDF 等)
    CGContextStrokePath(ctx);
}

當(dāng)這個view要顯示的時候才會調(diào)用drawRect繪制圖形rect為當(dāng)前控件的bounds

繪制其他圖形
  • 曲線(UIBezier畫不了曲線)
// path:路徑
// controlPointX 150
// controlPointY 150
// 終點(diǎn)x
// 終點(diǎn)y
CGPathAddQuadCurveToPoint(path, NULL, 150, 150, 250, 50);
  • 圓形
- (void)drawRect:(CGRect)rect {
    // Drawing code
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(20, 20, 200, 200) cornerRadius:100];
    
    [path stroke];
}
  • 矩形
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(20, 20, 200, 200)];
// 如果path是封閉路徑 可以填充
[path fill];
  • 圓弧
// 起點(diǎn)是右邊中間(時鐘3點(diǎn)位置)
// Center 圓心
// radios 半徑
// startAngle 開始弧度
// endAngle 結(jié)束弧度
// clockwise yes順時針 NO逆時針
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(125, 125) radius:40 startAngle:0 endAngle:M_PI_2 clockwise:NO];
//
[path stroke];

  • 扇形(圓弧終點(diǎn)連到圓心 然后關(guān)閉路徑)
CGPoint circleCenter = CGPointMake(125, 125);
UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:circleCenter radius:40 startAngle:0 endAngle:M_PI_2 clockwise:YES];

[path addLineToPoint:circleCenter];
[path closePath];

[path stroke];

  • 餅狀圖(PieChart)
- (void)drawRect:(CGRect)rect {
    
    NSArray *arr = @[@25, @12, @13, @30, @20];
    CGFloat radius = rect.size.width * 0.5;
    CGPoint center = CGPointMake(radius, radius);
    
    CGFloat startAngle = -M_PI_2;
    CGFloat endAngle = 0;
    CGFloat angle = 0;
    
    for (NSNumber *value in arr) {
        CGFloat red = (arc4random() % 255) / 255.0f;
        CGFloat green = (arc4random() % 255) / 255.0f;
        CGFloat blue = (arc4random() % 255) / 255.0f;
        
        angle = [value floatValue] / 100.0f * (M_PI * 2);
        endAngle = startAngle + angle;
        UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
        
        [path addLineToPoint:center];
        [path closePath];
        [[UIColor colorWithRed:red green:green blue:blue alpha:1] set];
        [path fill];
        startAngle = endAngle;
    }
}

屏幕快照 2016-06-27 下午5.20.35.png
  • 柱狀圖(ColumnChart)
- (void)drawRect:(CGRect)rect {

    NSArray *arr = @[@10, @20, @30, @40];

    CGFloat x = 0;
    CGFloat y = 0;
    CGFloat w = 0;
    CGFloat h = 0;
    
    NSInteger i = 0;
    
    for (NSNumber *value in arr) {
        CGFloat red = (arc4random() % 255) / 255.0f;
        CGFloat green = (arc4random() % 255) / 255.0f;
        CGFloat blue = (arc4random() % 255) / 255.0f;
        
        w = rect.size.width / (2 * arr.count - 1);
        x = 2 * w * i;
        h = [value floatValue] / 100.0f * rect.size.height;
        y = rect.size.height - h;
        
        UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(x, y, w, h)];

        [[UIColor colorWithRed:red green:green blue:blue alpha:1] set];
        [path fill];
        i++;
    }

}

屏幕快照 2016-06-27 下午5.54.30.png
  • 繪制文字圖片
- (void)drawRect:(CGRect)rect {
    NSString *name = @"Sniper is a very very very very very very very very very very very very very very very very very very very very good boy";
    
    NSMutableDictionary *textAttr = [NSMutableDictionary dictionary];
    
    [textAttr setObject:[UIColor redColor] forKey:NSForegroundColorAttributeName];
    [textAttr setObject:[UIFont systemFontOfSize:30] forKey:NSFontAttributeName];
    // 設(shè)置文字描邊寬度
    [textAttr setObject:@3 forKey:NSStrokeWidthAttributeName];
    // 設(shè)置文字顏色
    [textAttr setObject:[UIColor greenColor] forKey:NSStrokeColorAttributeName];
    // 創(chuàng)建陰影對象
    NSShadow *shadow = [[NSShadow alloc] init];
    shadow.shadowBlurRadius = 3;
    shadow.shadowColor = [UIColor orangeColor];
    shadow.shadowOffset = CGSizeMake(4, 4);
    [textAttr setObject:shadow forKey:NSShadowAttributeName];
    // 文字的起點(diǎn) (不會換行)
//    [name drawAtPoint:CGPointZero withAttributes:textAttr];
    [name drawInRect:rect withAttributes:textAttr];
}

屏幕快照 2016-06-27 下午6.13.46.png
- (void)drawRect:(CGRect)rect {
    
    UIImage *img = [UIImage imageNamed:@"golee.png"];
    // 裁剪必須放在繪制之前
    UIRectClip(CGRectMake(0, 0, 50, 50));
    // 繪制
    //    [img drawInRect:rect]; // 填充
    [img drawAsPatternInRect:rect]; // 平鋪
}
屏幕快照 2016-06-27 下午6.36.56.png
CADisplayLink

如果在繪圖的時候需要用到定時器,通常

// CADisplayLink 每次屏幕刷新的時候都會調(diào)用 (屏幕一般一秒鐘刷新60次)
CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(timerChanged)];
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
- (void)timerChanged {
    // 這個方法不會讓drawRect馬上執(zhí)行,這個方法只是給當(dāng)前控件添加刷新的標(biāo)記,等下一次屏幕刷新的時候才會調(diào)用drawrect方法  用CADisplayLink 讓刷新明目和timer的時間間隔保持一致 防止卡頓
    [self setNeedsDisplay];
}
矩陣操作
- (void)drawRect:(CGRect)rect {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(50, 50)];
    
    [path addLineToPoint:CGPointMake(200, 200)];
    
    // 平移 x平移100 y平移50
    CGContextTranslateCTM(ctx, 50, 50);
    // 縮放
    CGContextScaleCTM(ctx, 2, 2);
    // 旋轉(zhuǎn) 45度
    CGContextRotateCTM(ctx, M_PI_4);
    // 矩陣操作必須要在添加路徑之前
    CGContextAddPath(ctx, path.CGPath);
    
    CGContextStrokePath(ctx);
}

注意點(diǎn):

drawRect 不可以手動調(diào)用,因?yàn)槲覀儾荒軇?chuàng)建圖形上下文 只能由系統(tǒng)幫我們創(chuàng)建,并且傳遞給drawRect
想重新繪制 調(diào)用setNeedsDisplay比較好用

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末前计,一起剝皮案震驚了整個濱河市胞谭,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌男杈,老刑警劉巖丈屹,帶你破解...
    沈念sama閱讀 221,430評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異伶棒,居然都是意外死亡旺垒,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,406評論 3 398
  • 文/潘曉璐 我一進(jìn)店門肤无,熙熙樓的掌柜王于貴愁眉苦臉地迎上來先蒋,“玉大人,你說我怎么就攤上這事宛渐【貉” “怎么了?”我有些...
    開封第一講書人閱讀 167,834評論 0 360
  • 文/不壞的土叔 我叫張陵窥翩,是天一觀的道長业岁。 經(jīng)常有香客問我,道長寇蚊,這世上最難降的妖魔是什么笔时? 我笑而不...
    開封第一講書人閱讀 59,543評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮仗岸,結(jié)果婚禮上允耿,老公的妹妹穿的比我還像新娘。我一直安慰自己扒怖,他們只是感情好右犹,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,547評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著姚垃,像睡著了一般。 火紅的嫁衣襯著肌膚如雪盼忌。 梳的紋絲不亂的頭發(fā)上积糯,一...
    開封第一講書人閱讀 52,196評論 1 308
  • 那天掂墓,我揣著相機(jī)與錄音,去河邊找鬼看成。 笑死君编,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的川慌。 我是一名探鬼主播吃嘿,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼梦重!你這毒婦竟也來了兑燥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,671評論 0 276
  • 序言:老撾萬榮一對情侶失蹤琴拧,失蹤者是張志新(化名)和其女友劉穎降瞳,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蚓胸,經(jīng)...
    沈念sama閱讀 46,221評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡挣饥,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,303評論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了沛膳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片扔枫。...
    茶點(diǎn)故事閱讀 40,444評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖锹安,靈堂內(nèi)的尸體忽然破棺而出短荐,到底是詐尸還是另有隱情,我是刑警寧澤八毯,帶...
    沈念sama閱讀 36,134評論 5 350
  • 正文 年R本政府宣布搓侄,位于F島的核電站,受9級特大地震影響话速,放射性物質(zhì)發(fā)生泄漏讶踪。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,810評論 3 333
  • 文/蒙蒙 一泊交、第九天 我趴在偏房一處隱蔽的房頂上張望乳讥。 院中可真熱鬧,春花似錦廓俭、人聲如沸云石。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,285評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽汹忠。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間宽菜,已是汗流浹背谣膳。 一陣腳步聲響...
    開封第一講書人閱讀 33,399評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留铅乡,地道東北人继谚。 一個月前我還...
    沈念sama閱讀 48,837評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像阵幸,于是被迫代替她去往敵國和親花履。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,455評論 2 359

推薦閱讀更多精彩內(nèi)容