什么是Quartz2D?
Quartz 2D是一个二维绘图引擎,同时支持iOS和Mac系统
Quartz 2D的API是纯C语言的来自于Core Graphics框架数据类型和函数都是以CG为前缀
CGContextRef\CGPathRef\CGContextStrokePath(ctx)
Quartz 2D能完成的工作
绘制图形 : 线条\三角形\矩形\圆\弧等
绘制文字
绘制\生成图片(图像)
读取\生成PDF
截图\裁剪图片
自定义UI控件
......
Quartz2D在iOS开发中的价值?
为了便于搭建美观的UI界面,iOS提供了UIKit框架,里面有各种各样的UI控件
UILabel:显示文字
UIImageView:显示图片
UIButton:同时显示图片和文字(能点击)
......
1>利用UIKit框架提供的控件,拼拼凑凑,能搭建和现实一些简单、常见的UI界面
2>但是,有些UI界面极其复杂、而且比较个性化,用普通的UI控件无法实现,这时可以利用Quartz2D技术将控件内部的结构画出来,自定义控件的样子
3>其实,iOS中大部分控件的内容都是通过Quartz2D画出来的
4>因此,Quartz2D在iOS开发中很重要的一个价值是:自定义view(自定义UI控件)
5>那么废话不多说,直接上
图形上下文
图形上下文(Graphics Context):是一个CGContextRef类型的数据
图形上下文的作用
保存绘图信息、绘图状态
决定绘制的输出目标(绘制到什么地方去?)
(输出目标可以是PDF文件、Bitmap或者显示器的窗口上)
相同的一套绘图序列,指定不同的Graphics Context,就可将相同的图像绘制到不同的目标上
//
// ViewController.h
// Quartz2D
//
// Created by 周昭 on 16/4/8.
// Copyright © 2016年 Jordan Zhou. All rights reserved.
//
#import
@interface ViewController : UIViewController
@end
//
// ViewController.m
// Quartz2D
//
// Created by 周昭 on 16/4/8.
// Copyright © 2016年 Jordan Zhou. All rights reserved.
//
#import "ViewController.h"
#import "ZZQuartz2D.h"
@interface ViewController ()
@property (nonatomic, weak) ZZQuartz2D *drawViw;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// 加载绘图view
[self setUpQuartz2DView];
// 重绘slider
[self setUpSlider];
}
/**
* 添加绘图view
*/
- (void)setUpQuartz2DView
{
ZZQuartz2D *drawViw = [[ZZQuartz2D alloc] initWithFrame:[UIScreen mainScreen].bounds];
drawViw.backgroundColor = [UIColor whiteColor];
[self.view addSubview:drawViw];
self.drawViw = drawViw;
}
/**
* 创建slider
*/
- (void)setUpSlider
{
UISlider *slider = [[UISlider alloc] init];
slider.minimumValue = 0;
slider.maximumValue = 100;
CGFloat sliderX = self.view.frame.size.width * 0.5;
CGFloat sliderY = self.view.frame.size.height * 0.7;
CGFloat sliderW = self.view.frame.size.width * 0.8;
CGFloat sliderH = 20;
slider.center = CGPointMake(sliderX, sliderY);
slider.bounds = CGRectMake(0, 0, sliderW, sliderH);
[self.view addSubview:slider];
// 类似于UISlider\UISwitch 这样的控件事件改变是其值的改变
[slider addTarget:self action:@selector(sizeChange:) forControlEvents:UIControlEventValueChanged];
}
/**
* 根据set方法来赋值并且在内部调用 setNeedsDisplay 重绘的方法
*/
- (void)sizeChange:(UISlider *)slider
{
self.drawViw.radius = slider.value;
}
@end
//
// ZZQuartz2D.h
// Quartz2D
//
// Created by 周昭 on 16/4/8.
// Copyright © 2016年 Jordan Zhou. All rights reserved.
//
#import
@interface ZZQuartz2D : UIView
/**
* 圆的半径
*/
@property (nonatomic, assign) float radius;
@end
//
// ZZQuartz2D.m
// Quartz2D
//
// Created by 周昭 on 16/4/8.
// Copyright © 2016年 Jordan Zhou. All rights reserved.
//
#import "ZZQuartz2D.h"
@interface ZZQuartz2D()
@property (nonatomic, assign) CGFloat snowY;
@end
@implementation ZZQuartz2D
/**
* 重写set方法
*/
- (void)setRadius:(float)radius
{
_radius = radius;
// 重绘的方法只能是自己调用
[self setNeedsDisplay];
}
/**
* 当你创建view的时候这个方法就会自动创建可见这个方法的重要性
*/
- (void)drawRect:(CGRect)rect {
#warning 这个方法只会调一次走一次
/*
drawLine(); 画线
graphicsContextStack(); 图形上下文栈(重点:这个原理流程见分析思路)
draw4Rect(); 画四边形
drawTriangle(); 画三角形
drawArc(); 画圆弧
drawCircle(); 画圆
drawCircle4(); 画1/4圆
drawImage(); 画图片
drawText(); 画文字
matrixOperation(); 矩阵操作
[self reDrawCircle]; 重绘(刷帧)
[self drawSnowAnimation]; 画出下雪的效果
*/
}
/**
* 画线\多条线\区分线段样式
*/
void drawLine()
{
// 1.获得图形上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.拼接图形(路径)
CGContextSetLineWidth(ctx, 10);
// 设置线段头尾部的样式
CGContextSetLineCap(ctx, kCGLineCapRound);
// 设置线段转折点的样式
CGContextSetLineJoin(ctx, kCGLineJoinRound);
#pragma mark ---- 这里要求区分画出俩条线它们的属性即 线宽\颜色\转角点不一样 这是一种做法 重新设置属性然后多次渲染
/** 第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, 130, 50);
CGContextAddLineToPoint(ctx, 100, 70);
// 3.渲染显示到view上面
CGContextStrokePath(ctx);
}
/**
* 图形上下文栈
*/
void graphicsContextStack()
{
// 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); 这个相比传递参数还多一点为什么不记住简单?
}
/**
* 画四边形
*/
void draw4Rect()
{
// 1.获得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.画矩形
CGContextAddRect(ctx, CGRectMake(50, 50, 150, 100));
// set : 同时设置为实心和空心颜色
// setStroke : 设置空心颜色
// setFill : 设置实心颜色
[[UIColor whiteColor] set];
// CGContextSetRGBFillColor(ctx, 0, 0, 1, 1);
// 3.绘制图形
CGContextFillPath(ctx);
}
/**
* 画三角形
*/
void drawTriangle()
{
// 1.获得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.画三角形
CGContextMoveToPoint(ctx, 0, 0);
CGContextAddLineToPoint(ctx, 100, 100);
CGContextAddLineToPoint(ctx, 150, 80);
// 关闭路径(连接起点和最后一个点)
CGContextClosePath(ctx); // CGContextAddLineToPoint(ctx, 0, 0); 在连回去也是ok的
CGContextSetRGBStrokeColor(ctx, 0, 1, 0, 1);
// 3.绘制图形
CGContextStrokePath(ctx);
}
/**
* 画圆弧
*/
void drawArc()
{
// 1.获得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.画圆弧
// x\y : 圆心
// radius : 半径
// startAngle : 开始角度
// endAngle : 结束角度
// clockwise : 圆弧的伸展方向(0:顺时针, 1:逆时针)
CGContextAddArc(ctx, 100, 100, 50, M_PI_2, M_PI, 0);
// 3.显示所绘制的东西
CGContextFillPath(ctx);
}
/**
* 画圆
*/
void drawCircle()
{
// 1.获得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.画圆
CGContextAddEllipseInRect(ctx, CGRectMake(50, 10, 100, 100));
CGContextSetLineWidth(ctx, 10);
// 3.显示所绘制的东西
CGContextStrokePath(ctx);
}
/**
* 画1/4圆
*/
void drawCircle4()
{
// 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);
}
/**
* 画图片
*/
void drawImage()
{
// 1.取得图片
UIImage *image = [UIImage imageNamed:@"jordan"];
// 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, 180, 100, 30) withAttributes:nil];
}
/**
* 画文字
*/
void drawText()
{
// 1.获得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 2.画矩形
CGRect cubeRect = CGRectMake(50, 50, 100, 100);
CGContextAddRect(ctx, cubeRect);
// 3.显示所绘制的东西
CGContextFillPath(ctx);
// 4.画文字
NSString *str = @"My mood is so bad!!!";
// [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];
}
/**
* 矩阵操作
*/
void matrixOperation()
{
// 1.获得上下文
CGContextRef ctx = UIGraphicsGetCurrentContext();
// 将ctx拷贝一份放到栈中
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);
// 矩阵操作
// CGContextScaleCTM(ctx, 0.5, 0.5);
CGContextStrokePath(ctx);
}
/**
* 裁剪操作
*/
void clipCirle()
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextSaveGState(ctx);
// 0.画圆
CGContextAddEllipseInRect(ctx, CGRectMake(100, 100, 50, 50));
// 裁剪
CGContextClip(ctx);
CGContextFillPath(ctx);
// 1.显示图片
UIImage *image = [UIImage imageNamed:@"jordan"];
[image drawAtPoint:CGPointMake(100, 100)];
CGContextRestoreGState(ctx);
CGContextAddRect(ctx, CGRectMake(0, 0, 50, 50));
CGContextFillPath(ctx);
}
/**
* 重绘(刷帧)
*/
- (void)reDrawCircle
{
CGContextRef ctx = UIGraphicsGetCurrentContext();
CGContextAddArc(ctx, 125, 125, self.radius, 0, M_PI * 2, 0);
CGContextFillPath(ctx);
}
/**
* 画出下雪的动画
*/
- (void)drawSnowAnimation
{
// 调用的比较频繁用 CADisplayLink @selector 调用系统自带的方法就够不要自己写
CADisplayLink *link = [CADisplayLink displayLinkWithTarget:self selector:@selector(setNeedsDisplay)];
[link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode];
// 这个是用定时器调用
// [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(setNeedsDisplay) userInfo:nil repeats:YES];
self.snowY+=5;
if (self.snowY >= self.frame.size.height) {
self.snowY = -100;
}
UIImage *image = [UIImage imageNamed:@"jordan"];
[image drawAtPoint:CGPointMake(0, self.snowY)];
}
#pragma mark ---- 那么在这里最后也给同学们推荐一个Quartz 2D绘图的博客写的更加详细 有同学需要做K线图\绘图\制表的可以借鉴
// http://donbe.blog.163.com
@end