iOS开发——Core Graphics绘图

我们在搭建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里了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,390评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,821评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,632评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,170评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,033评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,098评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,511评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,204评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,479评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,572评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,341评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,893评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,171评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,486评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,676评论 2 335

推荐阅读更多精彩内容

  • Core Graphics Framework是一套基于C的API框架,使用了Quartz作为绘图引擎。它提供了低...
    ShanJiJi阅读 1,499评论 0 20
  • --绘图与滤镜全面解析 概述 在iOS中可以很容易的开发出绚丽的界面效果,一方面得益于成功系统的设计,另一方面得益...
    韩七夏阅读 2,684评论 2 10
  • 目录: 主要绘图框架介绍 CALayer 绘图 贝塞尔曲线-UIBezierPath CALayer子类 补充:i...
    Ryan___阅读 1,652评论 1 9
  • 1、感恩金钱,让我能给孩子买书。谢谢你,我爱你。 2、感恩食物,让我享受了一顿丰盛的午餐。谢谢你,我爱你。 3、感...
    AW小队长阅读 273评论 0 1
  • 第一封 外面风大 跟我回家 第二封 留在我身边 远近我都接受 第三封 我没说过永远 只希望每个明天你都在 第四封 ...
    鸢灵阅读 525评论 0 3