·您现在的位置: 云翼网络 >> 文章中心 >> 网站建设 >> app软件开发 >> IOS开发 >> Quartz2D快速入门

Quartz2D快速入门

作者:佚名      IOS开发编辑:admin      更新时间:2022-07-23

Quartz2D

  • Quartz2D的API是纯C语言的

  • Quartz2D的API来自于Core Graphics框架

  • 数据类型和函数基本都以CG作为前缀

    • CGContextRef
    • CGPathRef
    • CGContextStrokePath(ctx);
    • ……

1.drawRect:中取得的上下文

  • 在drawRect:方法中取得上下文后,就可以绘制东西到view上

  • View内部有个layer(图层)属性,drawRect:方法中取得的是一个Layer Graphics Context,因此,绘制的东西其实是绘制到view的layer上去了

  • View之所以能显示东西,完全是因为它内部的layer

2.Quartz2D绘图的代码步骤

1.获得图形上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();

2.拼接路径(下面代码是搞一条线段)
CGContextMoveToPoint(ctx, 10, 10);
CGContextAddLineToPoint(ctx, 100, 100);

3.绘制路径
CGContextStrokePath(ctx); // CGContextFillPath(ctx);

3.常用拼接路径函数

新建一个起点
void CGContextMoveToPoint(CGContextRef c, CGFloat x, CGFloat y)

添加新的线段到某个点
void CGContextAddLineToPoint(CGContextRef c, CGFloat x, CGFloat y)

添加一个矩形
void CGContextAddRect(CGContextRef c, CGRect rect)

添加一个椭圆
void CGContextAddEllipseInRect(CGContextRef context, CGRect rect)

添加一个圆弧
void CGContextAddArc(CGContextRef c, CGFloat x, CGFloat y,
  CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise)

4.常用绘制路径函数

Mode参数决定绘制的模式
void CGContextDrawPath(CGContextRef c, CGPathDrawingMode mode)

绘制空心路径
void CGContextStrokePath(CGContextRef c)

绘制实心路径
void CGContextFillPath(CGContextRef c)

提示:一般以CGContextDraw、CGContextStroke、CGContextFill开头的函数,都是用来绘制路径的

5.图形上下文栈的操作

将当前的上下文copy一份,保存到栈顶(那个栈叫做”图形上下文栈”)
void CGContextSaveGState(CGContextRef c)

将栈顶的上下文出栈,替换掉当前的上下文
void CGContextRestoreGState(CGContextRef c)
  • 具体实现
- (void)drawRect:(CGRect)rect {
    // 获得上下文
    CGContextRef ref = UIGraphicsGetCurrentContext();
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(50, 150)];
    [path addLineToPoint:CGPointMake(250, 150)];

    // 保存一个状态
    CGContextSaveGState(ref);

    CGContextSetLineWidth(ref, 20);
    [[UIColor redColor] set];

    CGContextAddPath(ref, path.CGPath);
    CGContextStrokePath(ref);

    path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(150, 50)];
    [path addLineToPoint:CGPointMake(150, 250)];
    // 还原状态
    CGContextRestoreGState(ref);

    CGContextAddPath(ref, path.CGPath);
    CGContextStrokePath(ref);

}

6.矩阵操作

  • 利用矩阵操作,能让绘制到上下文中的所有路径一起发生变化
    缩放
void CGContextScaleCTM(CGContextRef c, CGFloat sx, CGFloat sy)

旋转
void CGContextRotateCTM(CGContextRef c, CGFloat angle)

平移
void CGContextTranslateCTM(CGContextRef c, CGFloat tx, CGFloat ty)
  • 具体实现
// CG:core graphics
- (void)drawRect:(CGRect)rect {

    // 1.获得上下文
    CGContextRef ref =  UIGraphicsGetCurrentContext();
    // 2.描述路径
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 200, 100)];

    // 平移
    CGContextTranslateCTM(ref, 100, 100);
    // 旋转
    CGContextRotateCTM(ref, M_PI_4);
    // 缩放
    CGContextScaleCTM(ref, 0.5, 0.5);

    // 3.添加路径到上下文
    CGContextAddPath(ref, path.CGPath);

    // 4.渲染路径
    CGContextFillPath(ref);

}

7.Quartz2D的内存管理

  • 使用含有“Create”或“Copy”的函数创建的对象,使用完后必须释放,否则将导致内存泄露

  • 使用不含有“Create”或“Copy”的函数获取的对象,则不需要释放

  • 如果retain了一个对象,不再使用时,需要将其release掉

  • 可以使用Quartz 2D的函数来指定retain和release一个对象。例如,如果创建了一个CGColorSpace对象,则使用函数CGColorSpaceRetain和CGColorSpaceRelease来retain和release对象。

  • 也可以使用Core Foundation的CFRetain和CFRelease。注意不能传递NULL值给这些函数

Quartz2D简单的操作

1.画直线

  • 原始方法
/** 原始方法画直线三 */
- (void)drawThree
{
    // 1. 图形上下文
    CGContextRef ref = UIGraphicsGetCurrentContext();

    // 2.描述路径
    CGContextMoveToPoint(ref, 50, 50);
    CGContextAddLineToPoint(ref, 100, 200);

    // 3. 渲染
    CGContextStrokePath(ref);
}

/** 原始方法画直线er */
- (void)drawLineTwo
{
    // 1. 图形上下文
    CGContextRef ref =  UIGraphicsGetCurrentContext();
    // 2. 描述路径
    CGMutablePathRef path = CGPathCreateMutable();

    CGPathMoveToPoint(path, NULL, 50, 50);

    CGPathAddLineToPoint(path, NULL, 200, 250);

    // 默认第二条线以第一条线的终点为起点
    CGPathAddLineToPoint(path, NULL, 30, 200);
    // 3. 添加路径到图形上下文
    CGContextAddPath(ref, path);
    // 4. 渲染上下文
    CGContextStrokePath(ref);
}

/** 原始方法画直线一 */
- (void)drawLineOne
{
    // 1.拿到图形上下文
    CGContextRef ref = UIGraphicsGetCurrentContext();

    // 2.描述路径
    CGMutablePathRef  path = CGPathCreateMutable();
    // 添加起点
    CGPathMoveToPoint(path, NULL, 50, 50);
    // 添加一条线到终点
    CGPathAddLineToPoint(path, NULL, 200, 200);

    // 设置颜色
    [[UIColor redColor] set];

    // 3.添加路径到上下文
    CGContextAddPath(ref, path);

    // 4.渲染上下文
    CGContextStrokePath(ref);

}
  • 贝塞尔
/** 贝塞尔曲线画直线 */
- (void)besizer
{
    // UIKit提供的
    UIBezierPath *path = [UIBezierPath  bezierPath];
    [path moveToPoint:CGPointMake(50, 50)];
    [path addLineToPoint:CGPointMake(100, 200)];
    [[UIColor greenColor] set];
    [path stroke];
}

2.画曲线

/** 画曲线,只能用原始方法 */
- (void)drawQuadratic
{
    CGContextRef ref = UIGraphicsGetCurrentContext();
    CGContextMoveToPoint(ref, 50, 50);

    /* Append a quadratic curve from the current point to `(x, y)', with control
     point `(cpx, cpy)'. */
    // (150,20)是控制点,控制曲线
    // (100, 150)是曲线终点
    CGContextAddQuadCurveToPoint(ref, 150, 20, 100, 150);

    CGContextStrokePath(ref);
}

3.画扇形

/** 贝塞尔画扇形 */
- (void)bezierArc
{
    CGFloat radius = self.bounds.size.width * 0.5;
    // 贝塞尔画圆的时候,起点startAngle是三点钟方向,clockwise是yes表示顺时针,反之表示逆时针。
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(radius, radius) radius:radius-2 startAngle:0 endAngle:M_PI_2 clockwise:YES];
    [path addLineToPoint:CGPointMake(radius, radius)];
    [path fill];
}

4.下载进度

/** 什么时候调用: 控制器的view即将显示的时候调用 */
/** viewDidLoad->viewWillAppear->drawRect->viewDidAppear*/
/** drawRect不能手动调用,因为图形上下文我们自己创建不了,自能由系统创建 */
- (void)drawRect:(CGRect)rect {
    CGFloat radius = MIN(self.bounds.size.width, self.bounds.size.height)  * 0.5;
    CGFloat endAngle = self.slider * M_PI * 2 - M_PI_2;
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(radius, radius) radius:radius-2 startAngle:-M_PI_2 endAngle:endAngle clockwise:YES];
    [path stroke];
}

- (void)setSlider:(CGFloat)slider
{
    _slider = slider;
    // 重绘
    [self setNeedsDisplay];
}

5.画饼状图

- (void)drawRect:(CGRect)rect {

    NSArray *arrData = [NSArray randomArray];
    CGFloat radius = self.bounds.size.width * 0.5;
    CGPoint center = CGPointMake(radius, radius);

    UIBezierPath *path = nil;
    CGFloat startAngle = 0;
    CGFloat endAngle = 0;
    for (int i = 0; i<arrData.count; i++) {
        // 起点角度等于上一个的终点角度
        startAngle = endAngle;
        // 终点角度等于起点角度+自身的弧度
        endAngle = startAngle + ([arrData[i] floatValue]/100)*M_PI*2;
        path = [UIBezierPath bezierPathWithArcCenter:center radius:radius-2 startAngle:startAngle endAngle:endAngle clockwise:YES];
        [path addLineToPoint:center];

        [[UIColor colorWithRandom] set];
        [path fill];
    }
}

- (NSArray *)randomArr
{
    // +1 避免随机出来的是0
    int count = arc4random_uniform(10) + 1;
    int max = 100;
    int random = 0;
    NSMutableArray *arrData = [NSMutableArray array];
    for(int i = 0; i<count; i++)
    {
        // 避免随机出来的是0
        random = arc4random_uniform(max) + 1;
        [arrData addObject:@(random)];
        if (random == max) {
            break;
        }
        max -= random;
    }

    if (max) {
        [arrData addObject:@(max)];
    }
    return arrData;
}

/** 点击的时候,就重绘一次 */
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self setNeedsDisplay];
}

6.画柱状图

- (void)drawRect:(CGRect)rect
{
    NSArray *arrData = [NSArray randomArray];
    // 总个数(包括间距+柱状图)
    NSInteger postCount = 2 * arrData.count - 1;
    // 宽度
    CGFloat postW = self.bounds.size.width / postCount;

    UIBezierPath *path = nil;
    CGFloat x = 0;
    CGFloat y = 0;
    CGFloat h = 0;
    for (int i = 0; i < arrData.count; i++) {
        x = i * 2 * postW;
        h = ([arrData[i] floatValue] / 100) * self.bounds.size.height;
        y = self.bounds.size.height - h;
        path = [UIBezierPath bezierPathWithRect:CGRectMake(x, y, postW, h)];

        [[UIColor randomColor] set];

        [path fill];
    }
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self setNeedsDisplay];
}

7.画文字和图片

// 默认情况下:
// [str drawAtPoint:CGPointMake(0, 0) withAttributes:dict]; 不会换行
// [str drawInRect:rect withAttributes:dict]; 会自动换行
// [image drawAtPoint:CGPointMake(0, 0)];默认绘制的图片和图片大小一样
// [image drawInRect:rect];会把图片大小索缩放成跟rect大小一样
// [image drawaspatternInRect:self.bounds]; 会自动进行平铺
//
- (void)drawRect:(CGRect)rect
{
    UIImage *image = [UIImage imageNamed:@"001"];
    // 可以进行裁剪,但是必须放在绘制之前
    UIRectClip(CGRectMake(0, 0, 50, 50));
    [image drawAsPatternInRect:self.bounds];
}

- (void)drawStr
{
    NSString *str = @"Say_Alin,文能提笔控萝莉,武能编码调bug";

    NSDictionary *dict = @{NSFontAttributeName:[UIFont systemFontOfSize:40], NSForegroundColorAttributeName:[UIColor redColor], NSStrokeWidthAttributeName:@10};


    //    [str drawAtPoint:CGPointMake(0, 0) withAttributes:dict];


    [str drawInRect:self.bounds withAttributes:dict];
}

- (void)drawImage
{
    UIImage *image = [UIImage imageNamed:@"黄人"];
    //    [image drawAtPoint:CGPointMake(0, 0)];
    [image drawInRect:self.bounds];
}