Core Graphics 一: CGContext基本绘制

2020-09-23  本文已影响0人  Trigger_o

概览

硬件 -> OpenGL/core graphics -> core animation -> UI Kit/ App Kit


底层到上层

先看一下文档,打开xcode help的developer documentation


core graphics的api

先从最主要的部分进入
1.CGContext
Graphics Context:图形上下文,也就是画布,绘制完成后,将画布放到view中显示.
主要分为绘制,管理和配置等几个部分.
获取画布(CGContextRef对象)可以在uiview中重写- (void)drawRect:(CGRect)rect,也可以获取CALayer的画布,这里先从drawRect方法开始.
CGContext的绘制是绘制图形,基本上由路径的构建和填充策略组成

2.构建路径

CGContextRef context = UIGraphicsGetCurrentContext();
CGContextMoveToPoint(context, 100, 100); //画笔移动到(100,100)
CGContextAddLineToPoint(context, 200, 100); //向(200,100)画一条线
CGContextDrawPath(context, kCGPathStroke); 

kCGPathStroke是CGPathDrawingMode枚举,后面详细介绍

void CGContextAddArc(CGContextRef c, CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise);

xy是圆心坐标,radius是半径,startAngle是起始的角度,endAngle是结束的角度,clockwise是画圆弧的方向顺序,1为顺时针,0是逆时针.

CGContextAddArc(context, 100, 200, 50, M_PI/2, M_PI/2*3, 1);
CGContextDrawPath(context, kCGPathStroke);

如果是顺时针,则从圆心左边开始,为0,顺时针,往上90度为M_PI/2,以此类推,如果是逆时针,则从圆心右边开始,逆时针往上90度为M_PI/2,以此类推.

圆弧

CGContextAddArcToPoint函数

CGContextMoveToPoint(context, 190, 190);
CGContextAddArcToPoint(context, 200, 200, 300, 50, 100);
CGContextDrawPath(context, kCGPathStroke);

这个方法是从currentPoint(A)开始,再给定两个点B,C,然后再给一个半径,会画出一个和AB,BC两条线相切的圆弧以及A到圆弧的线段这样一个图形,
CGContextMoveToPoint和CGContextAddLineToPoint都会产生currentPoint.

CGContextAddArcToPoint
这个方法是用来解决图形上拼接圆弧的场景,只使用CGContextAddArc有时候很难把线段和圆弧连接上.

CGContextAddQuadCurveToPoint,二阶贝塞尔曲线,画出来的就是一个抛物线

CGContextMoveToPoint(context, 100, 290);
CGContextAddQuadCurveToPoint(context, 150, 80, 200, 390);
CGContextDrawPath(context, kCGPathStroke);

用两个点确定的一条曲线,和currentPoint组成两条线,与曲线相切


CGContextAddQuadCurveToPoint
二阶动画

CGContextAddCurveToPoint,三阶贝塞尔曲线

CGContextMoveToPoint(context, 300, 50);
CGContextAddCurveToPoint(context, 20, 300, 100, 300, 150, 350);
CGContextDrawPath(context, kCGPathStroke);

三个点可以确定一个曲线,当然这里没有算上currentPoint


CGContextAddCurveToPoint
三阶动画
CGPoint sPoints[4];//坐标点
sPoints[0] =CGPointMake(100, 220);//坐标1
sPoints[1] =CGPointMake(130, 220);//坐标2
sPoints[2] =CGPointMake(130, 160);//坐标3
sPoints[3] =CGPointMake(230, 160);//坐标4
CGContextAddLines(context, sPoints, 4);//添加线
CGContextDrawPath(context, kCGPathStroke); //根据坐标绘制路径

参数需要一个CGPoint数组和一个点的数量,需要小于等于数组长度


CGContextAddLines
CGContextAddRect(context, CGRectMake(200, 100, 100, 150));
CGContextDrawPath(context, kCGPathStroke);

绘制一个矩形,与currentPoint无关.

绘制一组矩形CGContextAddRects.

CGRect sRects[4];
    sRects[0] = CGRectMake(100, 100, 30, 30);
    sRects[1] = CGRectMake(100, 130, 30, 30);
    sRects[2] = CGRectMake(100, 160, 30, 30);
    sRects[3] = CGRectMake(100, 190, 30, 30);
    CGContextAddRects(context, sRects, 4);
    CGContextDrawPath(context, kCGPathStroke);
CGContextAddRects
CGContextAddEllipseInRect(context, CGRectMake(100, 100, 300, 120));
    CGContextDrawPath(context, kCGPathStroke);

画一个内切于给定矩形的椭圆


CGContextAddEllipseInRect
CGPoint sPoints[4];//坐标点
    sPoints[0] =CGPointMake(100, 220);//坐标1
    sPoints[1] =CGPointMake(130, 220);//坐标2
    sPoints[2] =CGPointMake(130, 160);//坐标3
    sPoints[3] =CGPointMake(230, 160);//坐标4
    CGContextAddLines(context, sPoints, 4);//添加线
    CGContextClosePath(context);//封闭路径
    CGContextDrawPath(context, kCGPathStroke); //根据坐标绘制路径
CGContextClosePath

3.填充路径

CGContextClearRect(context, CGRectMake(0, 0, 150, 300));

self.view.backgroundColor = UIColor.whiteColor;
    DrawView *view = [[DrawView alloc]initWithFrame:[UIScreen mainScreen].bounds];
    view.backgroundColor = [[UIColor alloc]initWithRed:0.0 green:1.0 blue:1.0 alpha:0.99];
    [self.view addSubview:view];

CGContextClearRect的效果取决于view是否不透明,这里透明度设置为.99,左上角被切除,露出下面的vc,如果透明度是1,则左上角会变成黑色.


清除左上角
黑色
void CGContextDrawPath(CGContextRef c, CGPathDrawingMode mode);

typedef CF_ENUM (int32_t, CGPathDrawingMode) {
  kCGPathFill,
  kCGPathEOFill,
  kCGPathStroke,
  kCGPathFillStroke,
  kCGPathEOFillStroke
};


CGContextAddEllipseInRect(context, CGRectMake(100, 100, 300, 120));
    CGContextAddEllipseInRect(context, CGRectMake(120, 120, 200, 80));
    CGContextAddEllipseInRect(context, CGRectMake(140, 140, 150, 50));
    CGContextDrawPath(context, kCGPathEOFill);

这个mode主要是两种策略,填充和描边
填充又有直接填充和奇偶规则两种
奇偶规则可以理解为,有一个向量横穿已经构建好的路径,遇到的第一个边为1,第二个边为2,那么1和2之间填充,再遇到3,2和3不填充,再遇到4,3和4填充


奇偶规则

4.设置绘制的样式属性

void CGContextSetLineDash(CGContextRef c, CGFloat phase, const CGFloat *lengths, size_t count);

CGFloat lengths[4] = {10.0,5.0,15.0,5.0};
CGContextSetLineDash(context, 0, lengths, 4);

phase表示第一段虚线从第几个点开始
lengths表示虚线的规则,比如{10,10}就是画10个点,跳过10个点
count是lengths的长度

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextMoveToPoint(context, 100, 100); //画笔移动到(100,100)
    CGContextAddLineToPoint(context, 200, 100); //向(200,100)画一条线
    CGContextAddLineToPoint(context, 150, 150);
    CGContextSetLineWidth(context, 4);
    CGContextSetLineJoin(context, kCGLineJoinRound);
    CGContextSetLineCap(context, kCGLineCapRound);
    CGFloat lengths[4] = {10.0,5.0,15.0,5.0};
    CGContextSetLineDash(context, 0, lengths, 4);
    CGContextDrawPath(context, kCGPathStroke);
各种样式

5.路径信息

CGContextDrawPath调用之后,current point就没了,如果需要继续绘制,就需要设置新的current point

    CGContextMoveToPoint(context, 100, 200);
    CGContextAddLineToPoint(context, 100, 100);
    CGContextAddLineToPoint(context, 200, 100);
    CGContextClosePath(context);
    CGContextSetFillColorWithColor(context, UIColor.blackColor.CGColor);
    CGContextDrawPath(context, kCGPathFill);
    
    CGContextMoveToPoint(context, 200, 100);
    CGContextAddLineToPoint(context, 200, 200);
    CGContextAddLineToPoint(context, 100, 200);
    CGContextClosePath(context);
    CGContextSetFillColorWithColor(context, UIColor.whiteColor.CGColor);
    CGContextDrawPath(context, kCGPathFill);
两个三角形

6.绘制图片

7.保存和重置上下文的设置
在绘制一个图形时,调用了一堆ContextSetxxx API之后,想要恢复context的设置,然后绘制下一个图形

    CGContextRef context = UIGraphicsGetCurrentContext();  //获取
    CGContextSaveGState(context);  //保存初始状态
    /* 进行各种设置 */
    /* CGContextDrawPath等绘图函数 */
    CGContextRestoreGState(context); //恢复初始
     /* 可以重新设置 */
     /* CGContextDrawPath等绘图函数 */

8.清除上下文

- (void)drawRect:(CGRect)rect{
    if(!self.shouldClear){
        //绘图
    }
}

//清除
self.shouldClear = YES;
[self setNeedsDisplay];

9.内存管理
Core Graphics的内存管理是创建和加减引用计数,Create相关的函数,会创建,retain相关的函数增加引用,Release相关的方法会减计数,计数为0会被释放.

上一篇下一篇

猜你喜欢

热点阅读