什么是Quartz2D
- Quartz2D是⼀个二维绘图引擎,同时支持iOS和Mac系统
Quartz2D的API是纯C语⾔言的Quartz2D的API来自于Core Graphics框架
Quartz2D的数据类型和函数基本都以CG作为前缀,例如下面2个类型:
1.CGContextRef
2.CGPathRef
Quartz2D的path
Points
void CGContextMoveToPoint (
CGContextRef c,
CGFloat x,
CGFloat y
);
指定一个点成为current point
Quartz会跟踪current point一般执行完一个相关函数后,current point都会相应的改变.
Lines
相关的几个函数
void CGContextAddLineToPoint (
CGContextRef c,
CGFloat x,
CGFloat y
);
创建一条直线,从current point到 (x,y)
然后current point会变成(x,y)
void CGContextAddLines (
CGContextRef c,
const CGPoint points[],
size_t count
);
创建多条直线,比如points有两个点,那么会画两条直线 从current point到 (x1,y1),
然后是(x1,y1)到(x2,y2)
然后current point会变成points中的最后一个点
Arcs
两种方法创建弧度
- 第一种
void CGContextAddArc (
CGContextRef c,
CGFloat x, //圆心的x坐标
CGFloat y, //圆心的x坐标
CGFloat radius, //圆的半径
CGFloat startAngle, //开始弧度
CGFloat endAngle, //结束弧度
int clockwise //0表示顺时针,1表示逆时针
);
假如想创建一个完整的圆圈,那么 开始弧度就是0 结束弧度是 2pi, 因为圆周长是 2pir.
最后,函数执行完后,current point就被重置为(x,y).
还有一点要注意的是,假如当前path已经存在一个subpath,那么这个函数执行的另外一个效果是
会有一条直线,从current point到弧的起点
- 第二种
void CGContextAddArcToPoint (
CGContextRef c,
CGFloat x1, //端点1的x坐标
CGFloat y1, //端点1的y坐标
CGFloat x2, //端点2的x坐标
CGFloat y2, //端点2的y坐标
CGFloat radius //半径
);
原理:首先画两条线,这两条线分别是 current point to (x1,y1) 和(x1,y1) to (x2,y2).
这样就是出现一个以(x1,y1)为顶点的两条射线,
然后定义半径长度,这个半径是垂直于两条射线的,这样就能决定一个圆了,更好的理解看下图,不过个人认为下图所标的 tangent point 1的位置是错误的。
最后,函数执行完后,current point就被重置为(x2,y2).
还有一点要注意的是,假如当前path已经存在一个subpath,那么这个函数执行的另外一个效果是
会有一条直线,从current point到(x1,y1)
Curves
画曲线,一般是一条直线,然后定义几个控制点,使直线变弯曲。
- 三次曲线函数
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坐标
);
假如第二个控制点(cp2x,cp2y)比(cp1x,cp1y) 更接近current point,那么会形成一个封闭的曲线
- 二次曲线函数
void CGContextAddQuadCurveToPoint (
CGContextRef c,
CGFloat cpx, //控制点 x坐标
CGFloat cpy, //控制点 y坐标
CGFloat x, //直线的终点 x坐标
CGFloat y //直线的终点 y坐标
);
执行完函数貌似current point不会变化,没有具体测试过
Ellipses椭圆
void CGContextAddEllipseInRect (
CGContextRef context,
CGRect rect //一矩形
);
如果矩形是一个正方形,那么画出来就是一个圆
Rectangles矩形
void CGContextAddRect (
CGContextRef c,
CGRect rect
);
Quartz2D画图练习
- 画线
- (void)drawRect:(CGRect)rect
{
// 1.获得图形上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.拼接图形(路径)
// 设置线段宽度
CGContextSetLineWidth(ctx, 10);
// 设置线段头尾部的样式
CGContextSetLineCap(ctx, kCGLineCapRound);
// 设置线段转折点的样式
CGContextSetLineJoin(ctx, kCGLineJoinRound);
/** 第1根线段 **/
// 设置颜色
CGContextSetRGBStrokeColor(ctx, 1, 0, 0, 1);
// 设置一个起点
CGContextMoveToPoint(ctx, 10, 10);
// 添加一条线段到(100, 100)
CGContextAddLineToPoint(ctx, 100, 100);
// 渲染一次
CGContextStrokePath(ctx);
/** 第2根线段 **/
// 设置颜色
CGContextSetRGBStrokeColor(ctx, 0, 0, 1, 1);
// 设置一个起点
CGContextMoveToPoint(ctx, 200, 190);
// 添加一条线段到(150, 40)
CGContextAddLineToPoint(ctx, 150, 40);
CGContextAddLineToPoint(ctx, 120, 60);
// 3.渲染显示到view上面
CGContextStrokePath(ctx);
}
- 矩形
// 1.获得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.画矩形
CGContextAddRect(ctx, CGRectMake(10, 10, 150, 50));
// set : 同时设置为实心和空心颜色
// setStroke : 设置空心颜色
// setFill : 设置实心颜色
[[UIColor greenColor] set];
// CGContextSetRGBFillColor(ctx, 0, 0, 1, 1);
// 3.绘制图形
CGContextFillPath(ctx);
- 三角形
// 1.获得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.画三角形
CGContextMoveToPoint(ctx, 0, 0);
CGContextAddLineToPoint(ctx, 100, 100);
CGContextAddLineToPoint(ctx, 150, 80);
// 关闭路径(连接起点和最后一个点)
CGContextClosePath(ctx);
//
CGContextSetRGBStrokeColor(ctx, 0, 1, 0, 1);
// 3.绘制图形
CGContextStrokePath(ctx);
- 画圆
// 1.获得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.画1/4圆
CGContextMoveToPoint(ctx, 100, 100);
CGContextAddLineToPoint(ctx, 100, 150);
CGContextAddArc(ctx, 100, 100, 50, -M_PI_2, M_PI, 1);
CGContextClosePath(ctx);
[[UIColor redColor] set];
// 3.显示所绘制的东西
CGContextFillPath(ctx);
- 圆弧
// 1.获得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.画圆弧
// x\y : 圆心
// radius : 半径
// startAngle : 开始角度
// endAngle : 结束角度
// clockwise : 圆弧的伸展方向(0:顺时针, 1:逆时针)
CGContextAddArc(ctx, 100, 10, 50, M_PI_2, M_PI, 0);
[[UIColor redColor] set];
// 3.显示所绘制的东西
CGContextFillPath(ctx);
- 圆
// 1.获得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.画圆
CGContextAddEllipseInRect(ctx, CGRectMake(50, 10, 100, 100));
CGContextSetLineWidth(ctx, 10);
[[UIColor greenColor] set];
// 3.显示所绘制的东西
CGContextStrokePath(ctx);
- 画文字和图片
// 1.取得图片
UIImage *image = [UIImage imageNamed:@"me"];
// 2.画
// [image drawAtPoint:CGPointMake(50, 50)];
// [image drawInRect:CGRectMake(0, 0, 150, 150)];
[image drawAsPatternInRect:CGRectMake(0, 0, 200, 200)];
// 3.画文字
NSString *str = @"为xxx所画";
[str drawInRect:CGRectMake(0, 0, 100, 30) withAttributes:nil];
- 画文字
// 1.获得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.画矩形
CGRect cubeRect = CGRectMake(50, 50, 100, 100);
CGContextAddRect(ctx, cubeRect);
// 3.显示所绘制的东西
CGContextFillPath(ctx);
// 4.画文字
NSString *str = @"你好";
// [str drawAtPoint:CGPointZero withAttributes:nil];
NSMutableDictionary *attrs = [NSMutableDictionary dictionary];
// NSForegroundColorAttributeName : 文字颜色
// NSFontAttributeName : 字体
attrs[NSForegroundColorAttributeName] = [UIColor redColor];
attrs[NSFontAttributeName] = [UIFont systemFontOfSize:50];
[str drawInRect:cubeRect withAttributes:attrs];
- 图形上下文栈
// 1.获得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 将ctx拷贝一份放到栈中
CGContextSaveGState(ctx);
// 设置绘图状态
CGContextSetLineWidth(ctx, 10);
[[UIColor redColor] set];
CGContextSetLineCap(ctx, kCGLineCapRound);
// 第1根线
CGContextMoveToPoint(ctx, 50, 50);
CGContextAddLineToPoint(ctx, 120, 190);
CGContextStrokePath(ctx);
// 将栈顶的上下文出栈,替换当前的上下文
CGContextRestoreGState(ctx);
// 第2根线
CGContextMoveToPoint(ctx, 10, 70);
CGContextAddLineToPoint(ctx, 220, 290);
CGContextStrokePath(ctx);
// CGContextDrawPath(ctx, kCGPathStroke);
- 矩阵操作
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
CGContextRotateCTM(ctx, M_PI_4 * 0.3);
CGContextScaleCTM(ctx, 0.5, 0.5);
CGContextTranslateCTM(ctx, 0, 150);
CGContextAddRect(ctx, CGRectMake(10, 10, 50, 50));
CGContextStrokePath(ctx);
CGContextRestoreGState(ctx);
CGContextAddEllipseInRect(ctx, CGRectMake(100, 100, 100, 100));
CGContextMoveToPoint(ctx, 100, 100);
CGContextAddLineToPoint(ctx, 200, 250);
CGContextStrokePath(ctx);
- 裁剪
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
// 0.画圆
CGContextAddEllipseInRect(ctx, CGRectMake(100, 100, 100, 100));
[[UIColor redColor] set];
// 裁剪
CGContextClip(ctx);
CGContextFillPath(ctx);
// 1.显示图片
UIImage *image = [UIImage imageNamed:@"1"];
[image drawAtPoint:CGPointMake(100, 100)];
CGContextRestoreGState(ctx);
CGContextAddRect(ctx, CGRectMake(0, 0, 50, 50));
[[UIColor yellowColor] set];
CGContextFillPath(ctx);
提示:- (void)drawRect:(CGRect)rect默认只会在view第一次显示的时候调用(只能由系统自动调用, 不能手动调用),如果要重新绘制调用 setNeedsDisplay方法。
定时器快速调用setNeedsDisplay,如果是一秒调用一次可以用NSTimer,如果0.1秒调用一次,要用CADisplayLink。每秒刷新60次。
CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(setNeedsDisplay)];
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
- CGMutablePathRef 的使用。
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 1.先创建一个路径
CGMutablePathRef linePath = CGPathCreateMutable();
// 2.拼接路径
CGPathMoveToPoint(linePath, NULL, 0, 0);
CGPathAddLineToPoint(linePath, NULL, 100, 100);
// 3.添加路径到上下文
CGContextAddPath(ctx, linePath);
CGMutablePathRef circlePath = CGPathCreateMutable();
CGPathAddArc(circlePath, NULL, 150, 150, 50, 0, M_PI * 2, 0);
CGContextAddPath(ctx, circlePath);
// 4.渲染
CGContextStrokePath(ctx);
CGPathRelease(linePath);
CGPathRelease(circlePath);
- 水印
+ (instancetype)waterImageWithBg:(NSString *)bg logo:(NSString *)logo
{
UIImage *bgImage = [UIImage imageNamed:bg];
// 上小文 : 基于位图(bitmap) , 所有的东西需要绘制到一张新的图片上去
// 1.创建一个基于位图的上下文(开启一个基于位图的上下文)
// size : 新图片的尺寸
// opaque : YES : 不透明, NO : 透明
// 这行代码过后.就相当于常见一张新的bitmap,也就是新的UIImage对象
// 1.创建一个基于位图的上下文(开启一个基于位图的上下文)
UIGraphicsBeginImageContextWithOptions(bgImage.size, NO, 0.0);
// 2.画背景
[bgImage drawInRect:CGRectMake(0, 0, bgImage.size.width, bgImage.size.height)];
// 3.画右下角的水印
UIImage *waterImage = [UIImage imageNamed:logo];
CGFloat scale = 0.2;
CGFloat margin = 5;
CGFloat waterW = waterImage.size.width * scale;
CGFloat waterH = waterImage.size.height * scale;
CGFloat waterX = bgImage.size.width - waterW - margin;
CGFloat waterY = bgImage.size.height - waterH - margin;
[waterImage drawInRect:CGRectMake(waterX, waterY, waterW, waterH)];
// 4.从上下文中取得制作完毕的UIImage对象
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
// 5.结束上下文
UIGraphicsEndImageContext();
return newImage;
}
- 图片裁剪
+ (instancetype)circleImageWithName:(NSString *)name borderWidth:(CGFloat)borderWidth borderColor:(UIColor *)borderColor
{
// 1.加载原图
UIImage *oldImage = [UIImage imageNamed:name];
// 2.开启上下文
CGFloat imageW = oldImage.size.width + 2 * borderWidth;
CGFloat imageH = oldImage.size.height + 2 * borderWidth;
CGSize imageSize = CGSizeMake(imageW, imageH);
UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0.0);
// 3.取得当前的上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 4.画边框(大圆)
[borderColor set];
CGFloat bigRadius = imageW * 0.5; // 大圆半径
CGFloat centerX = bigRadius; // 圆心
CGFloat centerY = bigRadius;
CGContextAddArc(ctx, centerX, centerY, bigRadius, 0, M_PI * 2, 0);
CGContextFillPath(ctx); // 画圆
// 5.小圆
CGFloat smallRadius = bigRadius - borderWidth;
CGContextAddArc(ctx, centerX, centerY, smallRadius, 0, M_PI * 2, 0);
// 裁剪(后面画的东西才会受裁剪的影响)
CGContextClip(ctx);
// 6.画图
[oldImage drawInRect:CGRectMake(borderWidth, borderWidth, oldImage.size.width, oldImage.size.height)];
// 7.取图
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
// 8.结束上下文
UIGraphicsEndImageContext();
return newImage;
}
- 屏幕截图
+ (instancetype)captureWithView:(UIView *)view
{
// 1.开启上下文
UIGraphicsBeginImageContextWithOptions(view.frame.size, NO, 0.0);
// 2.将控制器view的layer渲染到上下文
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
// 3.取出图片
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
// 4.结束上下文
UIGraphicsEndImageContext();
return newImage;
}
- 条纹背景
// 1.创建一行背景图片
CGFloat rowW = self.view.frame.size.width;
// CGFloat rowH = 40;
CGFloat rowH = 30;
UIGraphicsBeginImageContextWithOptions(CGSizeMake(rowW, rowH), NO, 0.0);
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 画矩形框
[[UIColor redColor] set];
CGContextAddRect(ctx, CGRectMake(0, 0, rowW, rowH));
CGContextFillPath(ctx);
// 2.画线
[[UIColor greenColor] set];
CGFloat lineWidth = 2;
CGContextSetLineWidth(ctx, lineWidth);
CGFloat dividerX = 0;
CGFloat dividerY = rowH - lineWidth;
CGContextMoveToPoint(ctx, dividerX, dividerY);
CGContextAddLineToPoint(ctx, rowW - dividerX, dividerY);
CGContextStrokePath(ctx);
// 3.取图
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
// 4.结束上下文
UIGraphicsEndImageContext();
// 5.设置为背景
self.textView.backgroundColor = [UIColor colorWithPatternImage:newImage];