iOS開發——Core Graphics繪圖

weixin_33912445發表於2016-06-04

我們在搭建UI介面時,有很多時候,我們會用到iOS自帶的繪圖功能來完成一些介面的效果,很常用也很方便。今天我們在這裡就一起討論一下iOS的繪圖功能。

  • CoreGraphics也稱為Quartz 2D 是UIKit下的主要繪圖系統,頻繁的用於繪製自定義檢視。Core Graphics是高度整合於UIView和其他UIKit部分的。Core Graphics資料結構和函式可以通過字首CG來識別。

  • 檢視可以通過子檢視、圖層或實現drawRect:方法來表現內容,如果說實現了drawRect:方法,那麼最好就不要混用其他方法了,如圖層和子檢視。自定義繪圖大部分是由UIKit或者Core Graphics來實現的。

  • 由於畫素是依賴於目標的,所以2D繪圖並不能操作單獨的畫素,我們可以從上下文(Context)讀取它。
    繪圖就好比在畫布上拿著畫筆機械的進行畫畫,通過制定不同的引數來進行不同的繪製。

iOS常見的圖形繪製

  • 畫線
  • 畫圓、圓弧、貝塞爾曲線
  • 畫矩形、橢圓形、多邊形
  • 繪製圖片
  • 繪製文字

iOS繪圖基礎

在繪圖之前,我們先來了解一下幾個基本的概念

  • context:上下文,ios繪圖的方法都需要傳一個上下文context,這個context在重寫uiview的drawRect的方法裡呼叫UIGraphicsGetCurrentContext()獲取

  • path:路徑,ios繪圖可以想象為你拿著一支筆去畫圖,畫幾條線或幾個點從而形成一個路徑,之後可以利用理解去填色或者描邊

  • stroke,fill 描邊和填充,每個路徑都需要填充或者描邊後才能在檢視中看見,他們都各自有很多樣式可以設定,常見的有顏色、粗細、漸變,連線樣式等等。

  • 畫圖可以使用預設路徑畫,或者單獨建立path畫圖,對應畫圖的api並不完全相同,是兩組名稱相似的api,兩組api常用的方法如下

CGContextMoveToPoint   //設定起點
CGContextClosePath     //連線起點和當前點
CGPathCreateMutable    //類似於 CGContextBeginPath
CGPathMoveToPoint      //類似於 CGContextMoveToPoint
CGPathAddLineToPoint   //類似於 CGContextAddLineToPoint
CGPathAddCurveToPoint  //類似於 CGContextAddCurveToPoint
CGPathAddEllipseInRect //類似於 CGContextAddEllipseInRect
CGPathAddArc           //類似於 CGContextAddArc
CGPathAddRect          //類似於 CGContextAddRect
CGPathCloseSubpath     //類似於 CGContextClosePath
CGContextAddPath       //函式把一個路徑新增到graphics

畫圖步驟

  • 獲取context
  • 設定Path
  • 填充或描邊路徑

關於填充顏色 有三種方式

  • 填充筆觸,就是隻給路徑描邊
  • 根據路徑填充顏色
  • 填充筆觸和顏色

填充顏色也分為非零繞數規則和奇偶規則,這個概念比較複雜難以解釋,大家可以百度看看或者畫幾個圖試試就明白。

CGContextStrokePath(ctx);    //描出路徑
CGContextFillPath(ctx)       //使用非零繞數規則填充當前路徑
CGContextDrawPath            //兩個引數決定填充規則,kCGPathFill表示用非零繞數規則,kCGPathEOFill表示用奇偶規則,kCGPathFillStroke表示填充,kCGPathEOFillStroke表示描線,不是填充
CGContextEOFillPath          //使用奇偶規則填充當前路徑
CGContextFillRect            //填充指定的矩形
CGContextFillRects           //填充指定的一些矩形
CGContextFillEllipseInRect    //填充指定矩形中的橢圓

常見的圖形繪製

準備工作

  • 新建一個檔案,繼承UIView
  • 重寫-(void)drawRect:(CGRect)rect方法
-(void)drawRect:(CGRect)rect{

    [super drawRect:rect];

    //獲取ctx
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    //設定畫圖相關樣式引數

    //設定筆觸顏色
    CGContextSetStrokeColorWithColor(ctx, [UIColor blackColor].CGColor);//設定顏色有很多方法,我覺得這個方法最好用
    //設定筆觸寬度
    CGContextSetLineWidth(ctx, 2);
    //設定填充色
    CGContextSetFillColorWithColor(ctx, [UIColor purpleColor].CGColor);
    //設定拐點樣式
    //    enum CGLineJoin {
    //        kCGLineJoinMiter, //尖的,斜接
    //        kCGLineJoinRound, //圓
    //        kCGLineJoinBevel //斜面
    //    };
    CGContextSetLineJoin(ctx, kCGLineJoinRound);
    //Line cap 線的兩端的樣式
    //    enum CGLineCap {
    //        kCGLineCapButt,
    //        kCGLineCapRound,
    //        kCGLineCapSquare
    //    };
    CGContextSetLineCap(ctx, kCGLineCapRound);
    //虛線線條樣式
    //CGFloat lengths[] = {10,10};

    //畫線
    [self drawLine:ctx];

    //畫圓、圓弧
    [self drawCircle:ctx];


    //畫矩形,畫橢圓,多邊形
    [self drawShape:ctx];

    //畫圖片
    [self drawPicture:ctx];

    //畫文字
    [self drawText:ctx];

    }

畫線

第一個方法我寫的比較詳細,寫了使用path的方式和直接畫線的方式。推薦使用path的方式畫線。 另外,第一個方法也寫了移動筆觸畫線和用點集合畫線。後面方法只會涉及其中一種,因為方法都比較類似。

  //畫線
    -(void)drawLine:(CGContextRef)ctx{

        //畫一條簡單的線
        CGPoint points1[] = {CGPointMake(10, 30),CGPointMake(300, 30)};
        CGContextAddLines(ctx,points1, 2);


        //畫線方法1,使用CGContextAddLineToPoint畫線,需要先設定一個起始點
        //設定起始點
        CGContextMoveToPoint(ctx, 50, 50);
        //新增一個點
        CGContextAddLineToPoint(ctx, 100,50);
        //在新增一個點,變成折線
        CGContextAddLineToPoint(ctx, 150, 100);


        //畫線方法2
        //構造線路徑的點陣列
        CGPoint points2[] = {CGPointMake(60, 60),CGPointMake(80, 120),CGPointMake(20, 300)};
        CGContextAddLines(ctx,points2, 3);


        //利用路徑去畫一組點(推薦使用路徑的方式,雖然多了幾行程式碼,但是邏輯更清晰了)
        //第一個路徑
        CGMutablePathRef path1 = CGPathCreateMutable();
        CGPathMoveToPoint(path1, &CGAffineTransformIdentity, 0, 200);
        //CGAffineTransformIdentity 類似於初始化一些引數
        CGPathAddLineToPoint(path1, &CGAffineTransformIdentity, 100, 250);
        CGPathAddLineToPoint(path1, &CGAffineTransformIdentity, 310, 210);
        //路徑1加入context
        CGContextAddPath(ctx, path1);
        //path同樣有方法CGPathAddLines(),和CGContextAddLines()差不多使用者,可以自己試下

        //描出筆觸
        CGContextStrokePath(ctx);
    }
    

畫矩形、橢圓形、多邊形

//畫矩形,畫橢圓,多邊形
-(void)drawSharp:(CGContextRef)ctx{

    CGContextSetFillColorWithColor(ctx, [UIColor redColor].CGColor);


    //畫橢圓,如果長寬相等就是圓
    CGContextAddEllipseInRect(ctx, CGRectMake(0, 250, 50, 50));

    //畫矩形,長寬相等就是正方形
    CGContextAddRect(ctx, CGRectMake(70, 250, 50, 50));


    //畫多邊形,多邊形是通過path完成的
    CGMutablePathRef path = CGPathCreateMutable();
    CGPathMoveToPoint(path, &CGAffineTransformIdentity, 120, 250);
    CGPathAddLineToPoint(path, &CGAffineTransformIdentity, 200, 250);
    CGPathAddLineToPoint(path, &CGAffineTransformIdentity, 180, 300);
    CGPathCloseSubpath(path);
    CGContextAddPath(ctx, path);


    //填充
    CGContextFillPath(ctx);


}

畫圖

    //畫圖片
    -(void)drawPicture:(CGContextRef)context{
        /*圖片*/
        UIImage *image = [UIImage imageNamed:@"head.jpeg"];
        [image drawInRect:CGRectMake(10, 300, 100, 100)];//在座標中畫出圖片
    }

畫文字

   //畫文字
    -(void)drawText:(CGContextRef)ctx{


        //文字樣式
        UIFont *font = [UIFont systemFontOfSize:18];
        NSDictionary *dict = @{NSFontAttributeName:font,
                               NSForegroundColorAttributeName:[UIColor whiteColor]};

        [@"hello world" drawInRect:CGRectMake(120 , 350, 500, 50) withAttributes:dict];
    }

畫圓、圓弧、貝塞爾曲線

** 畫圓和圓弧是一回事,只是起點和重點位置不同,畫圓畫弧線主要依賴於這幾個方法 CGContextAddArc, CGContextAddArcToPoint, CGContextAddCurveToPoint, CGContextAddQuadCurveToPoint 後面兩個方法是貝塞爾二次曲線和三次曲線 **

  //畫圓、圓弧
   -(void)drawCircle:(CGContextRef)ctx{

       CGContextSetStrokeColorWithColor(ctx, [UIColor purpleColor].CGColor);

       /* 繪製路徑 方法一
        void CGContextAddArc (
        CGContextRef c,
        CGFloat x,             //圓心的x座標
        CGFloat y,    //圓心的x座標
        CGFloat radius,   //圓的半徑
        CGFloat startAngle,    //開始弧度
        CGFloat endAngle,   //結束弧度
        int clockwise          //0表示順時針,1表示逆時針
        );
        */

       //圓
       CGContextAddArc (ctx, 100, 100, 50, 0, M_PI* 2 , 0);
       CGContextStrokePath(ctx);

       //半圓
       CGContextAddArc (ctx, 100, 200, 50, 0, M_PI*2, 0);
       CGContextStrokePath(ctx);

       //繪製路徑 方法二,這方法適合繪製弧度 ,端點p1和p2是弧線的控制點,類似photeshop中鋼筆工具控制曲線,還不明白請去了解貝塞爾曲線
       //    void CGContextAddArcToPoint(
       //                                CGContextRef c,
       //                                CGFloat x1,  //端點1的x座標
       //                                CGFloat y1,  //端點1的y座標
       //                                CGFloat x2,  //端點2的x座標
       //                                CGFloat y2,  //端點2的y座標
       //                                CGFloat radius //半徑
       //                                );

       //1/4弧度 * 4
       CGContextMoveToPoint(ctx, 200, 200);
       CGContextAddArcToPoint(ctx, 200, 100,300, 100, 100);
       CGContextAddArcToPoint(ctx, 400, 100,400, 200, 100);
       CGContextAddArcToPoint(ctx, 400, 300,300, 300, 100);
       CGContextAddArcToPoint(ctx, 200, 300,200, 200, 100);
       CGContextStrokePath(ctx);

       //貝塞爾曲線
       CGContextSetStrokeColorWithColor(ctx, [UIColor orangeColor].CGColor);

       //三次曲線函式
       //void CGContextAddCurveToPoint (
       //                               CGContextRef c,
       //                               CGFloat cp1x, //控制點1 x座標
       //                               CGFloat cp1y, //控制點1 y座標
       //                               CGFloat cp2x, //控制點2 x座標
       //                               CGFloat cp2y, //控制點2 y座標
       //                               CGFloat x,  //直線的終點 x座標
       //                               CGFloat y  //直線的終點 y座標
       //                               );

       CGContextMoveToPoint(ctx, 200, 200);
       CGContextAddCurveToPoint(ctx, 200, 0, 300, 200, 400, 100);
       CGContextStrokePath(ctx);

       //三次曲線可以畫圓弧,比如這裡畫一條之前用CGContextAddArcToPoint構成的圓弧
       CGContextMoveToPoint(ctx, 200, 200);
       CGContextAddCurveToPoint(ctx, 200, 100, 300, 100, 300 ,100);
       CGContextStrokePath(ctx);
       //二次曲線函式
       //void CGContextAddQuadCurveToPoint (
       //                                   CGContextRef c,
       //                                   CGFloat cpx,  //控制點 x座標
       //                                   CGFloat cpy,  //控制點 y座標
       //                                   CGFloat x,  //直線的終點 x座標
       //                                   CGFloat y  //直線的終點 y座標
       //                                   );

       CGContextMoveToPoint(ctx, 100, 100);
       CGContextAddQuadCurveToPoint(ctx, 200, 0, 300, 150);
       CGContextStrokePath(ctx);

   }

因為程式碼可以直接拷貝下去用,也就不上傳到Github上的demo裡了。

相關文章