iOS繪圖系統UIKit與Core Graphics

概述


iOS主要的繪圖系統有UIKit,Core Graphics,Core Animation,Core Image,Open GL等,本片博文主要介紹UIKit與Core Graphics的繪圖系統。

關於UIKit
iOS中的原生控件以UI前綴開頭的類名都是由UIKit繪製的。可以說我們進行開發打交道最多的就是UIKit這個框架。

關於Core Graphics
Core Graphics是iOS主要的繪圖系統,可以在屏幕,圖層,位圖,PDF或者打印機上繪製。在iOS中以CG前綴的類都屬於Core Graphics框架。


UIKit繪圖系統


視圖繪製

  • 視圖繪製的週期
    所有繪製的視圖都發生在主線程,如果在主線程進行耗時操作的話會阻礙繪製的更新,不能把主視圖的繪圖操作放到其他線程中,這對於當前的UIKit是線程不安全的。如果在其他線程對主視圖進行繪製會導致繪製出錯或崩潰。
  • 視圖繪製的方法
    setNeedsDispaly如果對視圖調用setNeedsDispaly方法,它會標記成爲需要刷新並且在下一繪圖週期中重新繪製,不過大部分UIKit視圖會在數據發生變化時自動進行重繪操作,因此除非想要在視圖上自定義繪圖,其他情況並不需要調用setNeedsDispaly方法。

通過UIKit繪圖

  • UIKit通過UIRectFrameUIRectFill可以進行一些簡單的繪製矩形的方法,如果想要繪製任意圖形需要用到UIBezierPath進行繪製,但是UIKit對一些高級的特性依然無能爲力比如陰影、漸變等效果。
  • UIBezierPath可以繪製任意的曲線和線條,因爲UIBezierPath擁有處理大部分線條、弧線、矩形、橢圓的簡單方法,因此UIBezierPath可以快速繪製大部分形狀。
  • 繪圖在系統提供的圖形上下文中完成後會調用drawRect:方法,所以我們自定義繪圖操作需要寫在drawRect:方法裏。

UIRectFrame與UIRectFill簡單的實現

- (void)drawRect:(CGRect)rect {
    [[UIColor greenColor] setFill]; //設置填充顏色
    UIRectFill(rect);   //設置填充區域
    [[UIColor redColor] setStroke]; //設置線條顏色
    UIRectFrame(CGRectMake(10, 10, 50, 50)); //設置矩形區域
}

實現效果

UIBezierPath的實現

- (void)drawRect:(CGRect)rect {
    CGSize size = rect.size;
    [[UIColor grayColor] setFill];
    UIRectFill(rect);       //設置一個背景色
    CGFloat margin = 10;    //圖像距離矩形上下邊框寬度
    CGFloat radius = rintf(MIN(size.height-margin, size.width-margin)/4);
    //確保圓弧能夠完整的畫在矩形框內,以矩形框最小的邊長1/4畫爲半徑畫圓弧
    CGFloat xOffset,yOffset;
    CGFloat offset = rintf((size.height - size.width)/2);
    if (offset>0) {
        xOffset = rint(margin/2);
        yOffset = offset;
    }
    else
    {
        xOffset = -offset;
        yOffset = rint(margin/2);
    }
    [[UIColor redColor] setFill];
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path addArcWithCenter:CGPointMake(radius * 2+xOffset, radius+yOffset)  //圓弧的中心
                    radius:radius   //圓弧的角度
                startAngle:-M_PI    //開始的角度
                  endAngle:0        //結束的角度
                 clockwise:YES];    //畫圓弧的方向(YES--順時針,NO--逆時針)
    [path addArcWithCenter:CGPointMake(radius * 3+xOffset, radius*2+yOffset)
                    radius:radius
                startAngle:-M_PI_2
                  endAngle:M_PI_2
                 clockwise:YES];
    [path addArcWithCenter:CGPointMake(radius * 2+xOffset, radius*3+yOffset)
                    radius:radius
                startAngle:0
                  endAngle:M_PI
                 clockwise:YES];
    [path addArcWithCenter:CGPointMake(radius +xOffset, radius*2+yOffset)
                    radius:radius
                startAngle:M_PI_2
                  endAngle:-M_PI_2
                 clockwise:YES];
    [path closePath];
    [path fill];
}

實現效果


Core Graphics繪圖系統


Core Graphics通過CGPath繪製簡單的實現

-(void)drawRect:(CGRect)rect
{
    [[UIColor grayColor] setFill];
    UIRectFill(rect);   //設置背景色
    CGContextRef ctx = UIGraphicsGetCurrentContext();   //獲取當前上下文
    CGContextSetStrokeColorWithColor(ctx, [[UIColor redColor] CGColor]);    //設置線條顏色
    CGContextSetLineJoin(ctx, kCGLineJoinRound);    //設置兩條線條連接點樣式
    CGContextSetLineWidth(ctx, 5);  //設置線條寬度
    CGMutablePathRef path = CGPathCreateMutable();  //創建路徑
    CGPathMoveToPoint(path, nil, 10, 10);   //設置路徑起始點
    CGPathAddLineToPoint(path, nil, 100, 100);  //移動到指定的Point
    CGPathAddLineToPoint(path, nil, 200, 10);
    CGContextAddPath(ctx, path);    //添加路徑到當前上下文
    CGPathRelease(path);    //釋放路徑
    CGContextStrokePath(ctx);   // 繪製當前上下文
}

實現效果

注意
Core Graphics屬於Core Fundation框架,Core Fundation不能ARC管理內存。所以Core Foundation對象需要手動釋放,即便啓用了ARC


iOS繪圖Tip


關於Core Graphics座標

drawRect:方法中,Core Graphics繪製的東西是上下顛倒的,我們正常是以左上角座標原點,而Core Graphics默認的是以左下角爲座標原點。如果想讓Core Graphics繪製的圖像以我們常用的左上角座標原點,只要在drawRect:方法中通過UIGraphicsGetCurrentContext()返回的上下文一切就正常了。如果使用自己創建的上下文,發現座標是以左下角則需要進行以下操作:

CGContextTranslateCTM(ctx, 0,rect.size.height);    //rect.size.height --- 當前view的高度
CGContextScaleCTM(ctx,1,-1);    //x軸座標不變,y軸座標取反

管理圖形上下文

  • CGContextSaveGState
    繪圖系統在調用drawRect:方法時創建的圖形上下文中包括大量信息,繪圖的顏色,線條的寬度,字體大小等。當此時某一時刻想更改這些信息,但是過後還想恢復之前的狀態就需要用到CGContextSaveGState來保存之前的狀態。

  • CGContextRestoreGState
    用來恢復之前由CGContextSaveGState保存的狀態

  • UIGraphicsPushContext
    UIKit繪製時只會對棧頂的context進行操作,所以當要繪製一個上下文時要把這個上下文push到管理上下文堆棧的棧頂。

  • UIGraphicsPopContext
    當繪製一個上下時要進行Push後才能操作,當繪製結束時需要Pop出棧。

  • UIGraphicsBeginImageContext
    UIGraphicsBeginImageContext是對UIGraphicsPushContextUIGraphicsPopContext操作的封裝,負責將舊的上下文入棧,爲新的上下文分配內存,創建新的上下文,翻轉座標系,並作爲當前上下文使用。

CGContextSaveGState與CGContextRestoreGState簡單實現

-(void)drawRect:(CGRect)rect
{
    CGContextRef ctx =  UIGraphicsGetCurrentContext();
    CGContextSetStrokeColorWithColor(ctx, [UIColor redColor].CGColor);  //設置繪製顏色
    CGContextSetLineWidth(ctx, 10);     //設置線條寬度
    CGContextMoveToPoint(ctx, 10, 10);
    CGContextAddLineToPoint(ctx, 100, 10);
    CGContextStrokePath(ctx);

    CGContextSaveGState(ctx);   //保存當前上下文狀態

    CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor); //設置繪製顏色
    CGContextSetLineWidth(ctx, 5);      //設置線條寬度
    CGContextMoveToPoint(ctx, 10, 30);
    CGContextAddLineToPoint(ctx, 100, 30);
    CGContextStrokePath(ctx);

    CGContextRestoreGState(ctx);    //取出之前保存的上下文狀態
    CGContextMoveToPoint(ctx, 10, 50);
    CGContextAddLineToPoint(ctx, 100, 50);
    CGContextStrokePath(ctx);
}

實現效果

UIGraphicsBeginImageContext使用

- (void)viewDidLoad {
    [super viewDidLoad];
    UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)];
    imageView.image = [self creatImage];
    [self.view addSubview:imageView];
}
-(UIImage *)creatImage
{
    const CGFloat kImageWidth = 100;
    const CGFloat kImageHeight = 100;   //設置圖片尺寸
    NSDictionary *attributeDic = @{NSFontAttributeName:[UIFont systemFontOfSize:14],NSForegroundColorAttributeName:[UIColor redColor]}; //設置字體屬性
    UIGraphicsBeginImageContext(CGSizeMake(kImageWidth, kImageWidth)); //創建上下文
    [@"GGGHub" drawInRect:CGRectMake(0, 0, kImageWidth, kImageHeight)
           withAttributes:attributeDic];    //把文字繪製到當前上下文
    CGImageRef textImage = UIGraphicsGetImageFromCurrentImageContext().CGImage;
    UIGraphicsEndImageContext();    //繪製結束
    return [UIImage imageWithCGImage:textImage];
}

實現效果

本篇博文參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章