14-Quartz 2D

抽屜效果的復(fù)雜實(shí)現(xiàn)(移動(dòng)縮放)

  1. 獲取上一次mainV的frame大小
    CGRect frame = self.mainV.frame;
  • 獲取屏幕的寬度和高度
    CGFloat screenW = [UIScreen mainScreen].bounds.size.width;
    CGFloat screenH = [UIScreen mainScreen].bounds.size.height;
  • X軸每平移一點(diǎn),Y軸需要移動(dòng)
    CGFloat offsetY = offsetX * kMaxY / screenW;
  • 獲取上一次的寬度和高度
    CGFloat preW = frame.size.width;
    CGFloat preH = frame.size.height;
  • 獲取當(dāng)前的高度
    CGFloat curH = preH - 2 * offsetY;
  • 獲取尺寸的縮放比例
    CGFloat scale = curH / preH;
  • 獲取當(dāng)前寬度
    CGFloat curW = preW * scale;
  • 獲取當(dāng)前X和當(dāng)前Y
    frame.origin.x += offsetX;
    CGFloat y = (screenH - curH) / 2;
    frame.origin.y = y;
    frame.size.height = curH;
    frame.size.width = curW;

什么是Quartz 2D

  • Quartz 2D是一個(gè)二維繪圖引擎,同時(shí)支持iOS和Mac系統(tǒng)
  • 繪圖的步驟:
    1. 獲取上下文
    • 創(chuàng)建路徑(描述路徑)
    • 把路徑添加到上下文
    • 渲染上下文
  • 通常在drawRect方法里面繪制圖形,因?yàn)橹挥性谶@個(gè)方法里面才能獲取到跟view的layer相關(guān)聯(lián)的圖形上下文
  • draw的調(diào)用時(shí)間:當(dāng)這個(gè)View要顯示的時(shí)候才會(huì)調(diào)用drawRect方法繪制圖形,其中drawRect方法中的rect參數(shù)為當(dāng)前控件的bounds

drawRect的加載順序

  • viewDidLoad --> viewWillApper --> drawRect -->viewDidApper

基本圖形的繪制

  • 方法一:原生繪制方法
#pragma mark - 最原始的繪圖方式
- (void)drawLine
{
    // 1.獲取圖形上下文
    // 目前我們所用的上下文都是以UIGraphics
    // CGContextRef Ref:引用 CG:目前使用到的類(lèi)型和函數(shù) 一般都是CG開(kāi)頭 CoreGraphics
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    
    // 2.描述路徑
    // 創(chuàng)建路徑
    CGMutablePathRef path = CGPathCreateMutable();
    
    // 設(shè)置起點(diǎn)
    // path:給哪個(gè)路徑設(shè)置起點(diǎn)
    CGPathMoveToPoint(path, NULL, 50, 50);
    
    // 添加一根線(xiàn)到某個(gè)點(diǎn)
    CGPathAddLineToPoint(path, NULL, 200, 200);
    
    // 3.把路徑添加到上下文
    CGContextAddPath(ctx, path);
    
    // 4.渲染上下文
    CGContextStrokePath(ctx);

}
  • 方法二
#pragma mark - 繪圖第二種方式
- (void)drawLine1
{
    // 獲取上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    
    // 描述路徑
    // 設(shè)置起點(diǎn)
    CGContextMoveToPoint(ctx, 50, 50);
    
    CGContextAddLineToPoint(ctx, 200, 200);
    
    // 渲染上下文
    CGContextStrokePath(ctx);

}
  • 方法三
#pragma mark - 繪圖第三種方式
- (void)drawLine2
{
    // UIKit已經(jīng)封裝了一些繪圖的功能
    
    // 貝瑟爾路徑
    // 創(chuàng)建路徑
    UIBezierPath *path = [UIBezierPath bezierPath];
    
    // 設(shè)置起點(diǎn)
    [path moveToPoint:CGPointMake(50, 50)];
    
    // 添加一根線(xiàn)到某個(gè)點(diǎn)
    [path addLineToPoint:CGPointMake(200, 200)];
    
    // 繪制路徑
    [path stroke];
    
    // NSLog(@"%@",NSStringFromCGRect(rect));

}

基本圖形繪制

  • 添加一根線(xiàn)到圓心
    [path addLineToPoint:center];
  • 封閉路徑,關(guān)閉路徑:從路徑的終點(diǎn)到起點(diǎn)
    [path closePath];
  • 填充:必須是一個(gè)完整的封閉路徑,默認(rèn)就會(huì)自動(dòng)關(guān)閉路徑
    [path fill];

重繪下載進(jìn)度條

  • 自定義下載進(jìn)度條ProgressView,并且聲明progress屬性,方便控制器向View傳遞下載進(jìn)度的值
  • 重寫(xiě)ProgressView的drawRect方法,創(chuàng)建貝瑟爾路徑
// 注意:drawRect不能手動(dòng)調(diào)用,因?yàn)閳D形上下文我們自己創(chuàng)建不了,只能由系統(tǒng)幫我們創(chuàng)建,并且傳遞給我們

- (void)drawRect:(CGRect)rect {
    // Drawing code
    
    // 創(chuàng)建貝瑟爾路徑
    CGFloat radius = rect.size.width * 0.5;
    CGPoint center = CGPointMake(radius, radius);
     
    CGFloat endA = -M_PI_2 + _progress * M_PI * 2;
    
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius - 2 startAngle:-M_PI_2 endAngle:endA clockwise:YES];
    
    [path stroke];
    
}
  • 重寫(xiě)setProgress方法,每次調(diào)用該方法都要對(duì)View進(jìn)行重繪
- (void)setProgress:(CGFloat)progress
{
    _progress = progress;
    
    // 重新繪制圓弧
    // [self drawRect:self.bounds];
    
    // 重繪,系統(tǒng)會(huì)先創(chuàng)建與view相關(guān)聯(lián)的上下文,然后再調(diào)用drawRect
    [self setNeedsDisplay];
}

畫(huà)餅圖

  • 生成隨機(jī)數(shù)組的方法
- (NSArray *)arrRandom
{
    int totoal = 100;
    
    NSMutableArray *arrM = [NSMutableArray array];
    
    int temp = 0; // 30 40 30
    for (int i = 0; i < arc4random_uniform(10) + 1; i++) {
        temp = arc4random_uniform(totoal) + 1;
        
        // 100 1~100
        
        // 隨機(jī)出來(lái)的臨時(shí)值等于總值,直接退出循環(huán),因?yàn)橐呀?jīng)把總數(shù)分配完畢,沒(méi)必要在分配。
        
        [arrM addObject:@(temp)];
        
        // 解決方式:當(dāng)隨機(jī)出來(lái)的數(shù)等于總數(shù)直接退出循環(huán)。
        if (temp == totoal) {
            break;
        }

        totoal -= temp;
        
    }
    // 100 30 1~100
    // 70 40 0 ~ 69 1 ~ 70
    // 30 25
    // 5
    
    if (totoal) {
        [arrM addObject:@(totoal)];
    }
    
    return arrM;
}
  • 生成隨機(jī)顏色的方法
- (UIColor *)colorRandom
{
    // 0 ~ 255 / 255
    // OC:0 ~ 1
    CGFloat r = arc4random_uniform(256) / 255.0;
    CGFloat g = arc4random_uniform(256) / 255.0;
    CGFloat b = arc4random_uniform(256) / 255.0;
    return [UIColor colorWithRed:r green:g blue:b alpha:1];
}
  • 根據(jù)數(shù)組繪制餅狀圖的方法
- (void)drawRect:(CGRect)rect {
    // Drawing code
    
    NSArray *arr = [self arrRandom];
    CGFloat radius = rect.size.width * 0.5;
    CGPoint center = CGPointMake(radius, radius);
    
    CGFloat startA = 0;
    CGFloat angle = 0;
    CGFloat endA = 0;
    
    for (int i = 0; i < arr.count; i++) {
        startA = endA;
        angle = [arr[i] integerValue] / 100.0 * M_PI * 2;
        endA = startA + angle;
        UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];
        
        [path addLineToPoint:center];
        
        [[self colorRandom] set];
        
        [path fill];
    }
     
}

繪制柱狀圖

  • 繪制柱狀圖的方法
  • 主要是確定每一個(gè)柱體的高度(height)、寬度(width)、左上角橫坐標(biāo)(x)和右上角橫坐標(biāo)(y)四個(gè)元素即可
- (void)drawRect:(CGRect)rect {
    // Drawing code
    
    NSArray *arr = [self arrRandom];
  
    CGFloat x = 0;
    CGFloat y = 0;
    CGFloat w = 0;
    CGFloat h = 0;
    
    for (int i = 0; i < arr.count; i++) {
        
        w = rect.size.width / (2 * arr.count - 1);
        x = 2 * w * i;
        h = [arr[i] floatValue] / 100.0 * rect.size.height;
        y = rect.size.height - h;
        
        UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(x, y, w, h)];
        
        [[self colorRandom] set];
        
        [path fill];
        
    }
    
}

繪制文字和圖片

  1. 通過(guò)drawAtPoint:withAttributes方法繪制文本
- (void)attrText
{
    
    // 繪制文字
    NSString *str = @"asfdsfsdf";
    
    // 文字的起點(diǎn)
    // Attributes:文本屬性

    NSMutableDictionary *textDict = [NSMutableDictionary dictionary];

    // 設(shè)置文字顏色
    textDict[NSForegroundColorAttributeName] = [UIColor redColor];

    // 設(shè)置文字字體
    textDict[NSFontAttributeName] = [UIFont systemFontOfSize:30];

    // 設(shè)置文字的空心顏色和寬度
    textDict[NSStrokeWidthAttributeName] = @3;
    textDict[NSStrokeColorAttributeName] = [UIColor yellowColor];

    // 創(chuàng)建陰影對(duì)象
    NSShadow *shadow = [[NSShadow alloc] init];
    shadow.shadowColor = [UIColor greenColor];
    shadow.shadowOffset = CGSizeMake(4, 4);
    shadow.shadowBlurRadius = 3;
    textDict[NSShadowAttributeName] = shadow;

    // 富文本:給普通的文字添加顏色,字體大小
    [str drawAtPoint:CGPointZero withAttributes:textDict];
}
  • 通過(guò)label繪制文本
- (void)drawText
{
    // 繪制文字
    
    NSString *str = @"asfdsfsdfasfdsfsdfasfdsfsdfasfdsfsdfasfdsfsdfasfdsfsdfasfdsfsdfasfdsfsdfasfdsfsdfasfdsfsdfasfdsfsdfasfdsfsdfasfdsfsdf";
    // 不會(huì)換行
    // [str drawAtPoint:CGPointZero withAttributes:nil];
    
    [str drawInRect:self.bounds withAttributes:nil];

}
  • 繪制圖片
- (void)drawRect:(CGRect)rect {
    // Drawing code
    
    // 超出裁剪區(qū)域的內(nèi)容全部裁剪掉
    // 注意:裁剪必須放在繪制之前,若放在繪制之后將沒(méi)有裁剪效果
    UIRectClip(CGRectMake(0, 0, 50, 50));
    
    UIImage *image = [UIImage imageNamed:@"001"];
    
    // 默認(rèn)繪制的內(nèi)容尺寸跟圖片尺寸一樣大
    // [image drawAtPoint:CGPointZero];
    
    // [image drawInRect:rect];
    // 繪圖
    [image drawAsPatternInRect:rect];
    
}

雪花(定時(shí)器操作)

  • 如果在繪圖的時(shí)候需要用到定時(shí)器,通常NSTimer很少用于繪圖,因?yàn)檎{(diào)度優(yōu)先級(jí)比較低,并不會(huì)準(zhǔn)時(shí)調(diào)用,所以在展示的時(shí)候會(huì)有卡頓的現(xiàn)象

  • 通常使用CADisplayLink完成繪圖過(guò)程中的定時(shí)任務(wù)操作,因?yàn)槠涿看纹聊凰⑿碌臅r(shí)候就會(huì)調(diào)用,屏幕一般一秒刷新60次
    CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(timeChange)];

      // 添加主運(yùn)行循環(huán)
      [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
    
  • 調(diào)用[self setNeedsDisplay]方法并不會(huì)馬上調(diào)用drawRect方法,其實(shí)這個(gè)方法只是給當(dāng)前控件添加刷新的標(biāo)記,等下一次屏幕刷新的時(shí)候才會(huì)調(diào)用drawRect方法,其和CaDisplayLink定時(shí)器實(shí)現(xiàn)了同步,所以看不到卡頓的現(xiàn)象

圖形上下文狀態(tài)棧

  • 如果以后用貝瑟爾繪制圖形[path stroke],上下文的狀態(tài)由貝瑟爾路徑?jīng)Q定
- (void)drawRect:(CGRect)rect {
    // Drawing code
    
    // 1.獲取上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    
    // 2.描述路徑
    // 第一根
    UIBezierPath *path = [UIBezierPath bezierPath];
    
    [path moveToPoint:CGPointMake(10, 125)];
    
    [path addLineToPoint:CGPointMake(240, 125)];
    
    // 把路徑添加到上下文
    // .CGPath 可以UIkit的路徑轉(zhuǎn)換成CoreGraphics路徑
    CGContextAddPath(ctx, path.CGPath);
    
    // 保存一份上下文的狀態(tài)
    CGContextSaveGState(ctx);
    
    // 設(shè)置上下文狀態(tài)
    CGContextSetLineWidth(ctx, 10);
    
    [[UIColor redColor] set];
   
    // 渲染上下文
    CGContextStrokePath(ctx);
    
    // 第二根

    // 2.描述路徑
    // 第一根
    path = [UIBezierPath bezierPath];
    
    [path moveToPoint:CGPointMake(125, 10)];
    
    [path addLineToPoint:CGPointMake(125, 240)];
    
    // 把路徑添加到上下文
    // .CGPath 可以UIkit的路徑轉(zhuǎn)換成CoreGraphics路徑
    CGContextAddPath(ctx, path.CGPath);
    
    // 還原狀態(tài)
    CGContextRestoreGState(ctx);
//    // 設(shè)置上下文狀態(tài)
//    CGContextSetLineWidth(ctx, 1);
//    
//    [[UIColor blackColor] set];
    
    // 渲染上下文
    CGContextStrokePath(ctx);
    
}

上下文矩陣操作

  • 通過(guò)上下文矩陣操作可以將繪制好的圖形,進(jìn)行平移、放大和旋轉(zhuǎn)操作
  • 注意:矩陣操作必須要在添加路徑之前,否則矩陣操作將無(wú)效
- (void)drawRect:(CGRect)rect {
    
    // 1.獲取上下文
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    
    // 2.描述路徑
   UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-100, -50, 200, 100)];
    
    [[UIColor redColor] set];
    
    // 上下文矩陣操作
    // 注意:矩陣操作必須要在添加路徑之前
    
    // 平移
    CGContextTranslateCTM(ctx, 100, 50);
    
    // 縮放
    CGContextScaleCTM(ctx, 0.5, 0.5);
    
    // 旋轉(zhuǎn)
    CGContextRotateCTM(ctx, M_PI_4);
    
    // 3.把路徑添加上下文
    CGContextAddPath(ctx, path.CGPath);

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

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

  • Quartz2D以及drawRect的重繪機(jī)制字?jǐn)?shù)1487 閱讀21 評(píng)論1 喜歡1一、什么是Quartz2D Q...
    PurpleWind閱讀 907評(píng)論 0 3
  • 本章中迄今為止的繪制實(shí)施例中大多會(huì)產(chǎn)生一個(gè)UIImage對(duì)象,主要是通過(guò)調(diào)用UIGraphicsBeginImag...
    shenzhenboy閱讀 1,427評(píng)論 0 4
  • 在iOS中隨處都可以看到絢麗的動(dòng)畫(huà)效果,實(shí)現(xiàn)這些動(dòng)畫(huà)的過(guò)程并不復(fù)雜,今天將帶大家一窺ios動(dòng)畫(huà)全貌。在這里你可以看...
    每天刷兩次牙閱讀 8,688評(píng)論 6 30
  • 我回來(lái)了。 很長(zhǎng)時(shí)間沒(méi)有寫(xiě)了,第一,公眾號(hào)整體在走下坡。第二,確實(shí)我掙不到多少錢(qián),我媳婦覺(jué)得,你天天用這么多時(shí)間,...
    6c676d940028閱讀 475評(píng)論 0 0
  • “為考研和工作糾結(jié)的妹紙,這是最好的決策方法” 教育部公布的2017年考研數(shù)據(jù),從去年的177萬(wàn)到了201萬(wàn),增加...
    白小白女性生涯規(guī)劃閱讀 3,092評(píng)論 1 37

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