iOS开发Quartz 2D基础

释放双眼,带上耳机,听听看~!

 

这里写图片描述

很早就想学quartz 2d了, 特别是贝塞尔曲线画图, 但是每次看到都是C的东西就感觉的头痛, 最近实在没忍住它的诱惑, 搜罗了一下网上的教程, 记录一下

Quartz 2D简介


Quartz 2D,是ios和mac os x环境下的二维绘图引擎。

  • Quartz2D提供了一下几种类型的Graphics Context:
      1. Bitmap Graphics Context
      1. PDF Graphics Context
      1. Window Graphics Context
      1. Layer Graphics Context
      1. Printer Graphics Context

涉及内容包括:基于路径的绘图,透明度绘图,遮盖,阴影,透明层,颜色管理。防锯齿渲染,生成PDF,以及PDF元数据相关处理。

所有的操作都在上下文中进行。所以在绘图之前需要获取该上下文并传入执行渲染的函数内。如果你正在渲染一副在内存中的图片,此时就需要传入图片所属的上下文。获得一个图形上下文是我们完成绘图任务的第一步,你可以将图形上下文理解为一块画布。如果你没有得到这块画布,那么你就无法完成任何绘图操作. 当获得一个Graphics Context后,可以使用Quartz 2D函数在上下文(context)中进行绘制、完成操作(如平移)、修改图形状态参数(如线宽和填充颜色)等

属性 和 方法


CGContextRef context = UIGraphicsGetCurrentContext(); 设置上下文
CGContextMoveToPoint 开始画线
CGContextAddLineToPoint 画直线

CGContextAddEllipseInRect 画一椭圆
CGContextSetLineCap 设置线条终点形状
CGContextSetLineDash 画虚线
CGContextAddRect 画一方框
CGContextStrokRect 指定矩形
CGContextStrokeLineWithWidth 指定矩形线宽度
CGContextStrokeLineSegments 一些直线

CGContextAddArc 画一曲线, 前两点为中心,中间两点为起始弧度,最后一数据位0则顺时针画,1则逆时针
CGContextAddArcToPoint(context,0,0,2,9,40);//线画两条线从point到第一点,从第一点到第2点的线 切割里面的圆。
CGContextSetShadowWithColor 设置阴影
CGContextSetRGBFillColor 这只填充颜色
CGContextSetRGBStrokeColor 画笔颜色设置
CGContextSetFillColorSpace 颜色空间填充
CGContextSetStrokeColorSpace颜色空间画壁设置
CGContextFillRect补充当前填充颜色的rect
CGContextSetAlaha透明度

CGContextTranslateCTM 改变画布的位置
CGContextSetLineWidth设置线的宽度
CGContextAddQuadCurveToPoint画曲线
CGContextStrokePath 开始绘制图片
CGContextDrawPath 设置绘制模式
CGContextClosePath 封闭当前线路
CGContextTranslateCTM(context,0,rect,size.height);
CGContextScaleCTM(context,1.0,-1.0,-1.0);翻转画布
CGContextSetInterpolationQuality背景内置颜色质量等级
CGImageCreateWithImageRect 从原图片中去小图。

字符串的写入可用NSString本身的画图方法 -(CGSize)drawInRect:(CGRect)rect withFont;(UIFont *)font lineBreakMode:(UILineBreakMode)lineBreakMode alignment:(UItextAlignment)alignment;来写进去即可

对图片放大缩小的功能就是慢了点
UIGraphicsBeginImageContext(newSize);
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

CGColorGetComponents ()返回颜色的各个值,以及透明度,可用只读const float 来接受是个数组

画图片
CGImageRefimage = CGImageRetain(img.CGImage);
CGContextDrawImage(context.CGRectMake(10.0,height-100.0,90.0,90.0),image);

实现渐变颜色填充方法
CGContextClip(context);
CGFloat color [] =
{
204.0 / 255.0, 224.0 / 255.0, 244.0 / 255.0, 1.00,

29.0 / 255.0, 156.0 / 255.0, 215.0 / 255.0, 1.00,

0.0 / 255.0, 50.0 / 255.0, 126.0 / 255.0, 1.00,

};

CGGradientRef gradient= CGGradientCreateWithColorComponents(rgb,colors,NULL,sizeof(colors)/(sizeof(colors[0])*4));
CGColorSpaceRelease(rgb);
CGContextDrawLinearGradient(context,gradient,CGPointMake(0.0,0.0),CGPointMake(0.0,self.frame.size.height),KCGGradientDrawsBeforStartLocation);

注:画完图后,必须先用CGContextStrokePath来描线,即形状
后用CGContextFillPath来填充形状内的颜色

设置当一个颜色覆盖上另外一个颜色,两个颜色怎么混合

默认方式是

result = (alpha * foreground) + (1 – alpha) * background

CGContextSetBlendMode :设置blend mode.

CGContextSaveGState :保存blend mode.

CGContextRestoreGState:在没有保存之前,用这个函数还原blend mode.

CGContextSetBlendMode 混合俩种颜色

简单使用


重写 - (void)drawRect:(CGRect)rect;方法

画直线

方法一

    //1. 获取 上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
//2. 设置颜色
[[UIColor greenColor] setFill];
//3. 画线
CGContextMoveToPoint(ctx, 20, 20);
CGContextAddLineToPoint(ctx, 200, 200);
CGContextSetLineWidth(ctx, 5);
CGContextSetRGBStrokeColor(ctx, 0.8, 0.5, 0.8, 1.0);
//4. 结束上下文
CGContextStrokePath(ctx);

方法二

在画线的时候,方法的内部默认创建一个path。它把路径都放到了path里面去。
1.创建路径 CGMutablePathRef 调用该方法相当于创建了一个路径,这个路径用来保存绘图信息。
2.把绘图信息添加到路径里边。
以前的方法是点的位置添加到ctx(图形上下文信息)中,ctx 默认会在内部创建一个path用来保存绘图信息。
在图形上下文中有一块存储空间专门用来存储绘图信息,其实这块空间就是CGMutablePathRef。
3.把路径添加到上下文中。

    CGFloat with = rect.size.width;
CGFloat height = rect.size.height;
/*
画线,可以创建一条路径(path)用来保存画线的绘图信息,如果又要重新画一个圆,那么就可以创建一条新的路径来专门保存画圆的绘图信息。
*/
// 1. 获取一个与视图相关联的上下文
CGContextRef context = UIGraphicsGetCurrentContext();
// 2. 构建路径
// 2.1 创建路径
CGMutablePathRef path = CGPathCreateMutable();
// 2.2 设置路径起点
CGPathMoveToPoint(path, NULL, 50, 50);
// 2.3 增加路径内容...
CGPathAddLineToPoint(path, NULL, 50, 420);
CGPathAddLineToPoint(path, NULL, 270, 420);
CGPathAddLineToPoint(path, NULL, 270, 50);
// 2.4 关闭路径
CGPathCloseSubpath(path);
// 3. 将路径添加到上下文
CGContextAddPath(context, path);
// 4. 设置上下文状态
// 4.1 设置边线颜色
CGContextSetRGBStrokeColor(context, 1, 0, 0, 1);
// 4.2 设置填充颜色
CGContextSetRGBFillColor(context, 0, 0, 1, 1);
// 4.2 设置线宽
CGContextSetLineWidth(context, 10);
// 4.3 设置线段连接样式
CGContextSetLineJoin(context, kCGLineJoinRound);
// 4.4 设置线段首位样式
CGContextSetLineCap(context, kCGLineCapRound);
// 4.5 设置虚线
CGFloat lengths[] = {20, 100};
CGContextSetLineDash(context, 100, lengths, 2);
// 5. 绘制路径
CGContextDrawPath(context, kCGPathEOFill);
// 6. 释放路径(如果创建对象的函数中包含create,copy或者retain字样,就需要释放!)
CGPathRelease(path);

画圆, 椭圆

    //1. 获取 上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
//2. 设置颜色
[[UIColor greenColor] setFill];
//3. 画圆(在矩形中)
CGContextAddEllipseInRect(ctx, CGRectMake(10, 10, with - 20, height - 20));
//结束上下文(填充, 不填充)
CGContextFillPath(ctx);
//CGContextStrokePath(ctx);

画弧arc

    /* Add an arc of a circle to the context's path, possibly preceded by a
straight line segment.
`(x, y)' is the center of the arc;
`radius' is its radius;
`startAngle' is the angle to the first endpoint of the arc;
`endAngle' is the angle to the second endpoint of the arc; and
`clockwise' is 1 if the arc is to be drawn clockwise(顺时针方向的), 0 otherwise.
`startAngle' and `endAngle' are measured in radians. */
CGContextAddArc(CGContextRef __nullable c, CGFloat x, CGFloat y,
CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise)

说明一点:
坐标问题 , 和我们平常的坐标系不一样
这里写图片描述

画矩形

你也可以画四条线

简单点的

    //1. 获取 上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
//2. 矩形
CGContextAddRect(ctx, CGRectMake(0, 0, with, height));
//3. 结束上下文
CGContextStrokePath(ctx);
    UIRectFill(CGRectMake(10, 10, 200, 300));

画圆角矩形

先介绍复杂的基础的, 使用UIBezierPath

CGFloat with = rect.size.width;
CGFloat height = rect.size.height / 2.0;
CGContextRef ctx = UIGraphicsGetCurrentContext();
[[UIColor colorWithWhite:0.600 alpha:1.000] set];
//CGContextMoveToPoint(ctx, 0, 20);
//0, 逆时针, 1顺时针
//不抗锯齿
//CGContextSetAllowsAntialiasing(ctx, NO);
/**
*  ctx: 上下文
*/
CGContextAddArc(ctx, radius, radius, radius, M_PI, M_PI_2 *3, 0);
CGContextAddArc(ctx, with-radius, radius, radius, M_PI_2 *3, 0, 0);
CGContextAddArc(ctx, with-radius, height-radius, radius, 0, M_PI_2, 0);
CGContextAddArc(ctx, radius, height-radius, radius, M_PI_2, M_PI, 0);
CGContextSetLineWidth(ctx, 1.5);
CGContextClosePath(ctx);
CGContextStrokePath(ctx);
CGContextAddArc(ctx, radius, radius+height, radius, M_PI, M_PI_2 *3, 0);
CGContextAddArc(ctx, with-radius, radius+height, radius, M_PI_2 *3, 0, 0);
CGContextAddArc(ctx, with-radius, height-radius+height, radius, 0, M_PI_2, 0);
CGContextAddArc(ctx, radius, height-radius+height, radius, M_PI_2, M_PI, 0);
CGContextSetLineWidth(ctx, 1.5);
CGContextClosePath(ctx);
CGContextStrokePath(ctx);

文字

    NSString *str = @"将文字绘制到指定的范围内, 如果一行装不下会自动换行, 当文字超出范围后就不显示";
NSDictionary *dic = @{           NSFontAttributeName: [UIFont systemFontOfSize:18]
};
CGRect frame = [str boundingRectWithSize:rect.size options:NSStringDrawingUsesLineFragmentOrigin |NSStringDrawingUsesFontLeading attributes:dic context:nil];
[str drawInRect:frame withAttributes:dic];

图像

    UIImage *image = [UIImage imageNamed:@"1.jpg"];
//利用drawAsPatternInRec方法绘制图片到layer, 是通过平铺原有图片
[image drawAsPatternInRect:rect];
//利用drawInRect方法绘制图片到layer, 是通过拉伸原有图片
[image drawInRect:rect];
//将图片绘制到指定的位置
//[image drawAtPoint:CGPointMake(100, 100)];

绘制渐变

//1. 定义渐变引用CGGradientRef
CGGradientRef gradient;
//2. 定义色彩空间引用
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
//3. 定义渐变颜色组件
//每四个数一组,分别对应r,g,b,透明度
CGFloat components[8] = {1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0};
//4. 定义颜色渐变位置
// 第一个颜色开始渐变的位置
// 第二个颜色结束渐变的位置
CGFloat locations[2] = {0, 1};
//5. 创建颜色渐进
gradient = CGGradientCreateWithColorComponents(colorSpace, components, locations, 2);
//6. 创建贝塞尔路径,是OC的,如果只是制定了渐变,没有指定剪切路径,就是整个视图的渐变
UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 200, 200)];
//7. 添加剪切路径
[path addClip];
//8. 绘制线性渐进
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawLinearGradient(context, gradient, CGPointMake(50, 50), CGPointMake(200, 50), kCGGradientDrawsAfterEndLocation);
//9. 释放颜色空间
CGColorSpaceRelease(colorSpace);
//10. 释放渐变引用
CGGradientRelease(gradient);

pdf

// 1. 上下文
// 1) 路径
// 2) 大小,指定为空,那么使用612 * 792大小作为pdf文件的页面大小
// 3) dict 
UIGraphicsBeginPDFContextToFile(@"/Users/apple/Desktop/demo.pdf", CGRectZero, nil);
// 2. 写入内容
// 在pdf里面是有页面的,一个页面一个页面的写入的
// 建立PDF页面
// 一个页面最多能够写入两张图片,因此写入6张图片需要三个页面
for (NSInteger i = 0; i < 6; i++) {
if (i % 2 == 0) {
UIGraphicsBeginPDFPageWithInfo(CGRectMake(0, 0, 612, 792), nil);
}
// 生成UIImage
UIImage *image = [UIImage imageNamed:[NSString stringWithFormat:@"NatGeo%02d.png", i + 1]];
// 写入
[image drawAtPoint:CGPointMake(0, 400 * (i % 2))];
}
// 3. 关闭上下文
UIGraphicsEndPDFContext();

贝塞尔曲线


个人感觉比较重要, 放到下一个文章中吧

注意

UIKit默认的坐标系统与Quartz不同。在UIKit中,原点位于左上角,y轴正方向为向下。UIView通过将修改Quartz的Graphics Context的CTM[原点平移到左下角,同时将y轴反转(y值乘以-1)]以使其与UIView匹配。这些都是系统自动帮我们完成。

参考

  1. iOS开发学习之Quartz2D绘图http://www.tuicool.com/articles/nQVBBn
  2. QUARTZ-2D绘图之图形上下文详解http://www.cnphp6.com/archives/66853
  3. http://www.360doc.com/content/13/1228/16/8310724_340792339.shtml
  4. http://www.cnblogs.com/xdream86/archive/2012/12/12/2814552.html

人已赞赏
iOS文章

iOS NSURLSession与NSURLConnection区别

2020-3-6 4:31:48

iOS文章

iOS开发UITableView分隔线间距为0

2020-3-6 10:59:44

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
有新消息 消息中心
搜索