Quartz2D
Quartz2D概述
- Quartz2D可以完成什么:
- 绘制图形:线,三角形,圆,椭圆等等
- 绘制文字(在image上)
- 绘制\生成图片
- 绘制\生成PDF
- 剪裁\切割图片
- 自定义UI控件
- 手势解锁
- 什么是图形上下文(Graphics Context):
- 是一个CGContextRef类型的数据
- 保存绘制的信息和状态(我们也可以理解成是一个画布,在这个画布上绘制)
- 决定绘制的输出目标(绘制到什么地方去?)(输出目标可以是PDF文件、Bitmap或者显示器的窗口上)
- Quartz2D可以获取到的图形上下文
- Bitmap Graphics Context
- PDF Graphics Context
- Window Graphics Context
- Layer Graphics Context
- Printer Graphics Context
Quartz2D对于图形的应用
Quartz2D的基本用法
- 在Quartz2D中苹果为我们提供了一套CoreGraphics框架,这是一套c语言的框架,下面的前两种方式就是采用这套,最后一种方式是在前面方式的基础上在OC中封装的一个类
- 无论是哪个方法,都必须在drawRect方法中执行,因为在drawRect方法中才能获取上下文
CGPath绘制
//CGPath绘制
- (void)CGPath
{
//获取图形上下文
CGContextRef ref = UIGraphicsGetCurrentContext();
//初始化一条线路
CGMutablePathRef pathref = CGPathCreateMutable();
//设置起点
//1.路径 2.旋转,缩放,平移等 3.起点的x轴坐标 4.起点的y轴坐标
CGPathMoveToPoint(pathref, nil, 10, 10);
//设置终点
CGPathAddLineToPoint(pathref, nil, 100, 100);
//把这个路线放到上下文上
//1.上下文 2.路径
CGContextAddPath(ref, pathref);
//释放路径(凡是c语言函数中带create,copy,一样要释放)
CGPathRelease(pathref);
//绘制
CGContextStrokePath(ref);
//填充
// CGContextFillPath(ref);
}
CGContexRef绘制
//CGContexRef绘制
- (void)CGContext
{
//获取图形上下文
CGContextRef ref = UIGraphicsGetCurrentContext();
// 设置起点
CGContextMoveToPoint(ref, 10, 10);
//设置终点(第一条线)
CGContextAddLineToPoint(ref, 100, 100);
//设置终点(第二条线)
CGContextAddLineToPoint(ref, 10, 100);
//设置线冒
CGContextSetLineCap(ref, kCGLineCapRound);
//设置拐角
CGContextSetLineJoin(ref, kCGLineJoinRound);
//设置线宽
CGContextSetLineWidth(ref, 10.0f);
//闭合
CGContextClosePath(ref);
//设置线的颜色
CGContextSetStrokeColorWithColor(ref, [UIColor redColor].CGColor);
//设置填充颜色
CGContextSetFillColorWithColor(ref, [UIColor yellowColor].CGColor);
//下面两个谁在前面执行那个
// //填充
// CGContextFillPath(ref);
// //绘制
// CGContextStrokePath(ref);
//由于上面两个方法只有一个能执行,所以为了两个都有效果,采用下面的方法,两个都设置(枚举)
CGContextDrawPath(ref, kCGPathFillStroke);
}
UIBezierPath的基本用法
//贝瑟尔基本用法
- (void)bezier
{
//初始化
UIBezierPath *path = [[UIBezierPath alloc] init];
//设置起点
[path moveToPoint:CGPointMake(10, 10)];
//设置终点(一条线)
[path addLineToPoint:CGPointMake(100, 100)];
//设置终点(第二条线)
[path addLineToPoint:CGPointMake(10, 100)];
//设置线宽
[path setLineWidth:10.0f];
//设直线冒
[path setLineCapStyle:kCGLineCapRound];
//设置拐角(两条线才能有拐角)
[path setLineJoinStyle:kCGLineJoinRound];
//设直线的颜色
[[UIColor redColor] setStroke];
//设置填充颜色
[[UIColor yellowColor] setFill];
//闭合路径
[path closePath];
//填充
[path fill];
//绘制
[path stroke];
}
//利用贝瑟尔绘制圆,椭圆和扇形
- (void)drawRound
{
//绘制圆
UIBezierPath *path = [UIBezierPath bezierPath];
// 1.圆心 2.半径 3. 开始的值(PI/ 2) 4. 结束的值 5. yes: 逆时针绘制 no:顺时针
[path addArcWithCenter:CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2) radius:100 startAngle:0 endAngle:M_PI * 2 clockwise:YES];
//绘制
[path stroke];
//绘制椭圆
UIBezierPath *path1 = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 100, 50)];
//绘制
[path1 stroke];
//扇形
UIBezierPath *path2 =[[UIBezierPath alloc] init];
//设置起点
[path2 moveToPoint:CGPointMake(100, 100)];
[path2 addArcWithCenter:CGPointMake(100, 100) radius:100 startAngle:0 endAngle:M_PI / 2 clockwise:YES];
//闭合
[path2 closePath];
//绘制
[path2 stroke];
}
自定义View
- 如何利用Quartz2D绘制东西到view上?
- 首先,得有图形上下文,因为它能保存绘图信息,并且决定着绘制到什么地方去
- 其次,那个图形上下文必须跟view相关联,才能将内容绘制到view上面
- 自定义view的步骤
- 新建一个类,继承自UIView
- 实现- (void)drawRect:(CGRect)rect方法,然后在这个方法中
- 取得跟当前view相关联的图形上下文
- 绘制相应的图形内容
- 利用图形上下文将绘制的所有内容渲染显示到view上面
- 注意:drawRect方法在view第一次显示到屏幕上会调用,在ViewDidLoad之后,viewWillAppear之前,如果想要在改变图形上下文之后调用drawRect方法显示改变后的效果,用setNeedsDisplay方法,调用完setNeedsDisplay方法之后,drawRect会被调用一次
绘制饼状图
- 基本思路:可以封装一个类继承与UIView,也可以给UIView写一个分类,这里采用继承
//在外部留好接口:传入数据和饼状图划分的颜色,以数组形式传入
@interface NewView : UIView
/** 数字数组 */
@property (nonatomic,strong) NSMutableArray *numberArray;
/** 颜色数组 */
@property (nonatomic,strong) NSMutableArray *colorArray;
/** 圆心 */
@property (nonatomic,assign) CGPoint centerPoint;
@end
//在.m中的drawRect方法中绘制
- (void)drawRect:(CGRect)rect {
//绘制圆
CGContextRef ref = UIGraphicsGetCurrentContext();
//设置圆心
CGPoint centerPoint = self.centerPoint;
//设置一个半径
CGFloat radius = 100;
//设置起始点
CGFloat starAngle = - M_PI_2;
//计算总和
CGFloat total = 0;
for (NSNumber *num in self.numberArray) {
total = total + [num floatValue];
}
//从头开始一个一个绘制,利用for循环
for (int i = 0; i < self.numberArray.count; i++) {
//计算百分比
CGFloat per = [self.numberArray[i] floatValue] / total ;
//设置终点
CGFloat endAngle = starAngle + 2 * M_PI * per;
//设置圆心为起点
CGContextMoveToPoint(ref,centerPoint.x , centerPoint.y);
//添加一条圆弧
CGContextAddArc(ref, centerPoint.x, centerPoint.y, radius, starAngle, endAngle, NO);
//闭合
CGContextClosePath(ref);
//设置填充颜色
CGContextSetFillColorWithColor(ref, [(UIColor *)self.colorArray[i] CGColor]);
//绘制
CGContextDrawPath(ref, kCGPathFillStroke);
//重置起点
starAngle = endAngle;
}
}
利用贝瑟尔曲线绘制曲线
- (void)drawRect:(CGRect)rect {
// Drawing code
//二元
UIBezierPath *path =[[UIBezierPath alloc] init];
//设置起点
[path moveToPoint:CGPointMake(10, 10)];
//设置曲线的属性
//参数1.曲线的终点,2.曲线的基准点
[path addQuadCurveToPoint:CGPointMake(100,100) controlPoint:CGPointMake(50, 100)];
//绘制
[path stroke];
// 三元
UIBezierPath *path = [[UIBezierPath alloc] init];
//设置起点
[path moveToPoint:CGPointMake(10, 100)];
//参数1.曲线的终点 2.曲线的第一个基准点 3.曲线的第二个基准点
[path addCurveToPoint:CGPointMake(100, 100) controlPoint1:CGPointMake(35, 25) controlPoint2:CGPointMake(75, 175)];
//绘制
[path stroke];
}
Quartz2D对于图片的应用
- 对于图片来说获取上下文可以不需要在drawRect中,有自己的获取方式
- 获取图片的上下文一定在 UIGraphicsBeginImageContext(),UIGraphicsEndImageContext()这两个方法中写,或者进行对图片的裁剪,旋转,擦除等等.
- 操作完图片之后可以用UIGraphicsGetImageFromCurrentImageContext()方法获得修改完之后的图片
- 除了图片可以这样修改,PDF格式也提供了类似的方法
根据颜色生成图片
- 实现原理:先获取一个固定大小的上下文,根据传进来的颜色,将上下文颜色填充,在image上平铺,输出image
//根据颜色生成图片
- (UIImage *)getImageWithColor:(UIColor *)color
{
//开始
// 1.图片的尺寸,2.是否是不透明的,3.图片的缩放比例
UIGraphicsBeginImageContext(CGSizeMake(200, 50));
//获取上下文
CGContextRef ref = UIGraphicsGetCurrentContext();
//设置颜色
CGContextSetFillColorWithColor(ref, color.CGColor);
//设置填充区域
CGContextFillRect(ref, CGRectMake(0, 0, 100, 100));
//填充
CGContextDrawPath(ref, kCGPathFillStroke);
//获取图片
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
//结束
UIGraphicsEndImageContext();
//输出图片
return image;
}
图片的剪裁
//图片的裁剪
- (UIImage *)clipWithImage:(UIImage *)image
{
//获取上下文(并给出这个上下文的尺寸)
UIGraphicsBeginImageContext(CGSizeMake(image.size.width / 2.0, image.size.height));
//这里的rect是值得在image的什么区域去绘制(下面这个写其实是绘制在整个image中)
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
//结束
UIGraphicsEndImageContext();
//输出图片
return UIGraphicsGetImageFromCurrentImageContext();
}
切圆
- 实现原理:先画出一个圆型的上下文,再讲图片画到画布上
//切圆
- (UIImage *)clipWithimage:(UIImage *)image
{
UIGraphicsBeginImageContext(image.size);
//获取上下文
CGContextRef ref = UIGraphicsGetCurrentContext();
//画圆
CGContextAddArc(ref, image.size.width / 2.0, image.size.height / 2.0, image.size.height / 2.0, 0, M_PI * 2, NO);
//裁剪画布
CGContextClip(ref);
// 把图片画到画布上
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
//结束
UIGraphicsEndImageContext();
//输出并返回
return UIGraphicsGetImageFromCurrentImageContext();
}
图片旋转,平移,缩放
//图片旋转
- (UIImage *)transWithImage:(UIImage *)image
{
UIGraphicsBeginImageContext(image.size);
//获取上下文
CGContextRef ref = UIGraphicsGetCurrentContext();
//缩放(旋转缩放平移是在上下文操作图片)
CGContextScaleCTM(ref, 0.6, 0.6);
//平移
CGContextTranslateCTM(ref, 50, 0);
//旋转 1.上下文 2.角度
CGContextRotateCTM(ref, M_PI_4);
//把图片画到画布上
[image drawInRect:CGRectMake(0, 0, image.size.width, image.size.height)];
//结束
UIGraphicsEndImageContext();
//返回绘制的图片
return UIGraphicsGetImageFromCurrentImageContext();
}
图片擦除(刮奖原理)(截屏也用到了这个的核心原理)
- 实现原理:当手指触摸到屏幕上的时候,去到触摸的某一个点,放大成一个正方形或者圆形,形成橡皮的感觉,在滑动过的区域将图片刮除,显示下面的label或者其他view,一定要保证刮除的我图片一定是透明的,否则看不到下面的label或者view
- (void)viewDidLoad {
[super viewDidLoad];
//初始化要显示在下面的提示label
UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(100, 100, 200, 50)];
label.textAlignment = NSTextAlignmentCenter;
label.text = @"恭喜您中奖了";
[self.view addSubview:label];
//初始化显示在上面的imageview(用上面的根据颜色生成图片方法生成一个灰色的图层,看起来像一种刮奖的图层)
self.imageView = [[UIImageView alloc] initWithImage:[self getImageWithColor:[UIColor grayColor]]];
self.imageView.frame = CGRectMake(100, 100, 200, 50);
[self.view addSubview:self.imageView];
}
//刮奖()
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
UITouch *touch = touches.anyObject;
CGPoint point = [touch locationInView:self.imageView];
//滑块区域(触碰到的点放大成正方形)
CGRect rect = CGRectMake( point.x - 10,point.y - 10, 20, 20);
//获取上下文(这里记得一定要透明)
UIGraphicsBeginImageContextWithOptions(self.imageView.bounds.size, NO, 0);
CGContextRef ref = UIGraphicsGetCurrentContext();
//把imageView的layer映射到上下文中(这个是核心,由于UIView本质上显示东西的layer层,所以实质是将imageView显示的东西全部复制给上下文,app中长用到的截屏就利用了这个原理)
[self.imageView.layer renderInContext:ref];
//清除划过的区域
CGContextClearRect(ref, rect);
UIImage *image =UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
//返回图片并不断的传给UIImageView上去显示
self.imageView.image = image;
}
绘制文字(以图片的形式输出)(给图片右下角绘制专属的唯一标示(也就是水印)就用到了这个原理)
//绘制文字
- (UIImage *)drawWithStr:(NSString *)str
{
//获取上下文
UIGraphicsBeginImageContext(self.view.frame.size);
//利用富文本设置文字的属性
NSDictionary *dic = @{NSFontAttributeName:[UIFont systemFontOfSize:14.0f],NSForegroundColorAttributeName:[UIColor redColor]};
//绘制在上下文中
[str drawInRect:CGRectMake(10, 10, 200, 100) withAttributes:dic];
//输出image
return UIGraphicsGetImageFromCurrentImageContext();
}