Quartz2D

相关资源

棋盘和手势解锁

chess.gif
gestureLock.gif

GitHub粒子发射和复制图层示例

GitHub粘性控件示例

GitHub弹性动画

CALayer分析

响应者手势分析

CAEmitter分析

Quartz2D

Quartz2D是一个二维绘图引擎,同时支持iOS和Mac系统。iOS中,大部分控件都是Quartz2D绘制出来的。这里需要重点说明一下,Quartz2D的接口(函数)和使用对象(或者结构体)定义在CoreGraphics框架和UIKit中。一般情况下我们使用UIKit下面提供的对象和接口就可以实现丰富的功能。复杂的情况下需要混合使用,或者只使用CoreGraphics框架。CoreGraphics是C语言框架,使用起来不如面向对象方便。

图形上下文

提到绘图,我们就得了解最基本的概念。图形上下文所表示的是图形绘制的平台。包含绘制参数以及需要执行一系列绘图命令的设备信息。图形上下文定义了包括绘制颜色、裁剪区域、曲线宽度以及绘制模式信息、文本字体信息、一些合成选项或者是一些其他的有关绘制的基本属性。看下图,了解一下上下文的分类:


CGContext.png

这里主要分析和用到了两种上下文:

1. Bitmap Graphics Context

位图上下文,在这个上下文上绘制或者渲染的内容,可以获取成图片(需要主动开启一个上下文来使用,使用完毕,一定要销毁或者关闭;所以这里也不需要在UIView 的 drawRect:方法里获取上下文了)。

开启和关闭上下文

// 开启一个图片(位图)上下文//size:上下文尺寸,opaque:不透明度,scale:如果设置为0.0,这个设置是屏幕的scale,例如iPhone6是2,iPhone6P是3。
UIGraphicsBeginImageContextWithOptions(CGSize size, BOOL opaque, CGFloat scale);
// 关闭位图上下文
UIGraphicsEndImageContext();

简单示例

  1. 打水印

     UIImage *image = [UIImage imageNamed:@"卡哇伊"];
     UIGraphicsBeginImageContextWithOptions(image.size, NO, 0.0);
     //把图片给绘制图片上下文.
     [image drawAtPoint:CGPointZero];
     //绘制文字
     NSString *str = @"I Love You";
     [str drawAtPoint:CGPointZero withAttributes:@{NSFontAttributeName : [UIFont systemFontOfSize:20]}];
     //生成图片
     UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
     //手动关闭上下文
     UIGraphicsEndImageContext();
    
     self.imageV.image = newImage;
    
    
printCharacters.png
  1. 擦图
- (void)viewDidLoad {
   [super viewDidLoad];
   // Do any additional setup after loading the view, typically from a nib.
   self.imageV.userInteractionEnabled = YES;
   //添加手势
   UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
   [self.imageV addGestureRecognizer:pan];
}

 - (void)pan:(UIPanGestureRecognizer *)pan{

   //获取当前手指所在的点
   CGPoint curP = [pan locationInView:self.imageV];
   CGFloat rectWH = 50;
   CGFloat x = curP.x - rectWH * 0.5;
   CGFloat y = curP.y - rectWH * 0.5;
   CGRect rect =   CGRectMake(x, y, rectWH, rectWH);
   
   //开启一个图片上下文.
   UIGraphicsBeginImageContextWithOptions(self.imageV.bounds.size, NO, 0);
   
   //获取当前的上下文.
   CGContextRef ctx = UIGraphicsGetCurrentContext();
   
   //把UImageViwe上面的图片给绘制到上下文.
   [self.imageV.layer renderInContext:ctx];
   
   //确定擦除区域
   CGContextClearRect(ctx, rect);
   
   //生成一张新图片
   UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
   
   //把上下文给关闭
   UIGraphicsEndImageContext();
   //给原来图片重新赋值
   self.imageV.image = newImage;

 }
erasePicture.gif
  1. 截屏
    //1.开启图片上下文.
    UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0);
    
    //获取当前的上下文.
    CGContextRef ctx =  UIGraphicsGetCurrentContext();
    
    //UIView之所能够显示,是因为layer.把层渲染给位图上下文.
    [self.view.layer renderInContext:ctx];
    
    //生成一张图片.
    UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
    
    //如何把图片转换成二进流.
    NSData *data = UIImagePNGRepresentation(newImage);
    [data writeToFile:@"/Users/Boat/Desktop/newImage.png" atomically:YES];
    
    //关闭上下文.
    UIGraphicsEndImageContext();
    

2. Layer Graphics Context

图层上下文,针对UI控件的上下文。我们已经很清楚,view之所以能显示内容,全靠layer(图层)。

UIView 的 drawRect:方法

drawRect: 这个是UIKit提供给UIView的方法,只有在此方法中我们才可以获取到与此View对象对应的图层上下文(CGContextRef);但是有时候我们在想,苹果为什么不直接给CALayer提供此方法呢?可能是我才疏学浅,毕竟QuartsCore也给我们提供了各种类型的layer,也许我们需要挖掘一下QuartsCore下面的CALayer。详情请参考顶部的相关资源

基本绘图

先通过基本绘图,我们可以总结用法以及原理。

  1. 简单直线
  // Drawing code
    NSLog(@"%s",__func__);
    NSLog(@"%@",NSStringFromCGRect(self.bounds));
    
    //1.取得一个跟View相关联的上下文.
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.描述路径
    UIBezierPath *path = [UIBezierPath bezierPath];
    //2.1.设置起点
    [path moveToPoint:CGPointMake(10, 100)];
    //2.1.添加一根线到某个点
    [path addLineToPoint:CGPointMake(200, 20)];
    
    //一个路径上面可以画多条线
    [path moveToPoint:CGPointMake(10, 150)];
    [path addLineToPoint:CGPointMake(200, 100)];
    
    //把上一条线的终点当作是下一条线的起点.
    [path addLineToPoint:CGPointMake(150, 200)];
    
    
    //设置上下文的状态
    //设置线的宽度
    CGContextSetLineWidth(ctx, 10);
    //设置线的连接样式
    CGContextSetLineJoin(ctx, kCGLineJoinBevel);
    //设置顶角的样式
    CGContextSetLineCap(ctx, kCGLineCapRound);
    //设置线的颜色
    [[UIColor greenColor] setStroke];
    //3.把路径添加到上下文
    CGContextAddPath(ctx, path.CGPath);
    //4.把上下文的内容显示View fill stroke
    CGContextStrokePath(ctx);
drawLine.png
  1. 简单曲线
//1.获取跟View相关联的上下文
  CGContextRef ctx =  UIGraphicsGetCurrentContext();
  //2.描述路径
  UIBezierPath *path = [UIBezierPath bezierPath];
  //2.1设置起点
  [path moveToPoint:CGPointMake(20, 200)];
  //2.2添加一条曲线到某个点.
  [path addQuadCurveToPoint:CGPointMake(200, 200) controlPoint:CGPointMake(100, 10)];

  CGContextSetLineWidth(ctx, 10);

  //3.把路径添加到上下文
  CGContextAddPath(ctx, path.CGPath);
  //4.把上下文的内容显示出来.
  CGContextStrokePath(ctx);
drawQuadCurve.png
  1. 简单矩形
//1.获取上下文
  CGContextRef ctx = UIGraphicsGetCurrentContext();
  //2.描述路径
  UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(50, 50, 100, 100)];
  //3.把路径添加到上下文
  CGContextAddPath(ctx, path.CGPath);
  
  [[UIColor yellowColor] set];
  
  //4.把上下文的内容显示
  CGContextFillPath(ctx);
drawRectangle.png
  1. 简单饼图

NSArray *dataArray = @[@25,@25,@25,@25];
//画饼图扇形
CGPoint center = CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5);
CGFloat radius = rect.size.width * 0.5 - 10;
CGFloat startA = 0;
CGFloat angle = 0;
CGFloat endA = 0;

for (NSNumber *num in dataArray) {
    startA = endA;
    angle = num.intValue / 100.0 * M_PI * 2;
    endA = startA + angle;
   UIBezierPath  *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:startA endAngle:endA clockwise:YES];
    [path addLineToPoint:center];
    [[self randomColor] set];
    [path fill];
}

//随机生成一个颜色

  • (UIColor *)randomColor{

    CGFloat r = arc4random_uniform(256) / 255.0;
    CGFloat g = arc4random_uniform(256) / 255.0;
    CGFloat b = arc4random_uniform(256) / 255.0;

    //0-255.
    // colorWithRed 0-1
    return [UIColor colorWithRed:r green:g blue:b alpha:1];
    }

 > ![drawPie.png](http://upload-images.jianshu.io/upload_images/3448645-7f76bb23decef3eb.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
 
 
> 现在基本可以总结使用方法:
> 
> 1. 获得上下文
> 
> 2. 绘制/拼接绘图路径
> 
> 3. 上下文当前栈设置,包括颜色,线条等
> 
> 4. 将路径添加到上下文
> 
> 5. 渲染上下文
> 
> Note:
> 
> 这里使用的是UIKit下面的贝塞尔曲线类,没用使用CoreGraphics的路径。
> 
> UIBezierPath包含很多对CoreGraphics的路径(Path)的封装,而且还提供直接渲染功能,当然还包括对图形上下文栈(CGContextRestoreGState)的封装。
> 
> 对于图形上下文栈(CGContextRestoreGState)这里不做说明,请去站内搜索。


#### UIKit对象直接绘图
> 注意,这里介绍的仍然是图层上下文(Layer Graphics Context)。这里相关知识不再介绍,也不再配图。有兴趣可以试一试。

1. 图片UIImage对象相关

  • (void)drawRect:(CGRect)rect {
    // Drawing code

    //1.加载图片
    UIImage *image = [UIImage imageNamed:@"001"];

    //2.绘制出来的图片,是保持原来图片
    // [image drawAtPoint:CGPointZero];
    //2. 把图片填充到这个rect当中.
    [image drawInRect:rect];
    // 添加裁剪区域 .把超区裁剪区域以外都裁剪掉
    UIRectClip(CGRectMake(0, 0, 50, 50));
    // [image drawAsPatternInRect:self.bounds];

}


2. 文字NSSting相关

NSString *str = @"辛为舟帅气侧漏";

//AtPoint:文字所画的位置
//withAttributes:描述文字的属性.
NSMutableDictionary *dict = [NSMutableDictionary dictionary];
//设置文字大小
dict[NSFontAttributeName] = [UIFont systemFontOfSize:50];

//设置文字颜色
dict[NSForegroundColorAttributeName] = [UIColor greenColor];
//设置描边宽度
dict[NSStrokeWidthAttributeName] = @2;
//设置描边颜色
dict[NSStrokeColorAttributeName] = [UIColor blueColor];

//设置阴影
NSShadow *shadow = [[NSShadow alloc] init];
//设置阴影的便宜量
shadow.shadowOffset = CGSizeMake(10, 10);
//设置阴影颜色
shadow.shadowColor = [UIColor greenColor];
//设置阴影模糊程序
shadow.shadowBlurRadius = 1;
dict[NSShadowAttributeName] = shadow;
//不会自动换行
[str drawAtPoint:CGPointZero withAttributes:dict];
//会自动换行.
[str drawInRect:self.bounds withAttributes:dict];  
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,458评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,454评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,171评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,062评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,440评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,661评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,906评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,609评论 0 200
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,379评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,600评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,085评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,409评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,072评论 3 237
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,088评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,860评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,704评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,608评论 2 270

推荐阅读更多精彩内容

  • Quartz2D以及drawRect的重绘机制字数1487 阅读21 评论1 喜欢1一、什么是Quartz2D Q...
    PurpleWind阅读 730评论 0 3
  • 什么是Quartz2D 是一个二维的绘图引擎,同时支持iOS和Mac系统 Quartz2D的API是纯C语言的,它...
    Mario_ZJ阅读 549评论 0 1
  • Quartz2D 简介 Quartz2D是二维(平面)的绘图引擎(经包装的函数库,方便开发者使用。也就是说苹果帮我...
    iOS_Cqlee阅读 608评论 0 2
  • Quartz2D 简介及用途 Quartz 2D 是一个二维绘图引擎,同时支持iOS和Mac系统,Quartz2D...
    45b645c5912e阅读 911评论 1 16
  • 常用链接 [1] d3官网主页,但是东西不多,因为主要都以github形式为主。 [2] d3例子,很丰富。 [3...