Quartz2D

什么是Quartz2D

  • 是一个二维的绘图引擎,同时支持iOS和Mac系统
  • Quartz2D的API是纯C语言的,它的API来自于Core Graphics框架,数据类型和函数,都是以CG开头的

Quartz2D的应用

  • 画基本线条,绘制文字,图片,截图,自定义UIView
  • 在开发中,可以将内部结构比较复杂控件,通过绘制,实现自定义控件

Quartz2D中的图形上下文是什么,有哪些类型

  • 图形上下文是一个CGContextRef类型的数据
  • 图形上下文是用来保存用户绘制的内容状态,并决定绘制到那个地方
  • 图形上下文的类型:
    • Bitmap Graphics Context(位图上下文)
    • PDF Graphics Context
    • Window Graphics Context
    • Layer Graphics Context(图层上下文,自定义UIView取得上下文就是图层上下文.UIView之所以能够显示就是因为他内部有一个图层)
    • Printer Graphics Context

自定义UIView的步骤

  • 1.先自定义UIView
  • 2.实现DrawRect方法
  • 3.在DrawRect方法中取得跟View相关联的上下文
  • 4.绘制路径(描述路径长什么样).
  • 5.把描述好的路径保存到上下文(即:添加路径到上下文)
  • 6.把上下文的内容渲染到View
  • 注意:获取的上下文,必须是与要绘制到的view相关联的,这样才能将上下文的内容绘制到view上

基本线条的绘制

  • 通过drawRect方法绘制
  • DrawRect方法作用?什么时候调用.
    • 作用 : 专用在这个方法当中绘图的.只有在这个方法当中才能取得跟View相关联的上下文.
    • 调用 : 是系统自己调用的, 它是当View显示的时候自动调用.
    • 参数(rect): 指的是当前view的bounds
    • drawRect会自动创建一个跟当前View相关联的上下文.
  • View上的绘制以及显示
    在drawRect:方法中取得上下文后,就可以绘制东西到view上
    View内部有个layer(图层)属性,drawRect:方法中取得的是一个Layer Graphics
    Context,因此,绘制的东西其实是绘制到view的layer上去了
    View之所以能显示东西,完全是因为它内部的layer

线段的绘制

  • 步骤:
    • 1.获取当前view的图形上下文
    • 2.描述路径
      • 2.1 设置路径的起点
      • 2.2 添加一根线到终点
    • 3.将绘制的路径添加到上下文中
    • 4.把上下文中的内容渲染到UIView的layer上(通过stoke或者fill的方式渲染)
-(void)drawRect:(CGRect)rect {
    //1.获取当前上下文(uigraphics开头)
    CGContextRef ctx =  UIGraphicsGetCurrentContext();

    //2.描述路径
    UIBezierPath *path = [UIBezierPath bezierPath];
    //2.1设置起点
    [path moveToPoint:CGPointMake(50, 200)];
    //2.1添加一根线到终点
    [path addLineToPoint:CGPointMake(200, 50)];

    //3.把绘制的路径添加到上下文
    //UIBezierPath=UIKit ->   CGPathRef=coreGraphics(将UIKit类型的path转换为CGPathRef类型的path)
    CGContextAddPath(ctx, path.CGPath);
    
    //4.把上下文的内容渲染UIView的layer.(stoke(描边),fill(填充))
    CGContextStrokePath(ctx);   
}
  • 设置/修改上下文的状态.
设置线的宽度
CGContextSetLineWidth(ctx, 10);
设置线的连接样式.
CGContextSetLineJoin(ctx, kCGLineJoinBevel);
设置线的顶角样式
CGContextSetLineCap(ctx, kCGLineCapRound);
设置线的颜色.还可以直接用set这种方法
[[UIColor greenColor] set];   
  • 如果在添加另一根线
    • 第一种方法:重新设置起点,添加一根线到某个点,一个UIBezierPath路径上面可以有多条线.
    • 第二种方法:直接在原来的基础上添加线.把上一条线的终点当做下一条线的起点.添加一根线到某个点直接在下面addLineToPoint:CGPointMake(200, 50)

曲线的绘制

-(void)drawQuadCurve {
    //1.获取当前上下文(uigraphics开头)
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //2.描述路径
    UIBezierPath *path = [UIBezierPath bezierPath];
    [path moveToPoint:CGPointMake(50, 250)];
    //添加一根曲线
    [path addQuadCurveToPoint:CGPointMake(250, 250) controlPoint:CGPointMake(150, 50)];
    
    //3.把绘制的路径添加到上下文
    //UIBezierPath=UIKit ->   CGPathRef=coreGraphics
    CGContextAddPath(ctx, path.CGPath);
    
    //4.把上下文的内容渲染到View的layer
    CGContextStrokePath(ctx);
}

矩形的绘制

 //画矩形
- (void)drawRect {
    //1.获取上下文
    CGContextRef ctx =  UIGraphicsGetCurrentContext();

    //2.描述路径
    /*
    (x,y)点决定了矩形左上角的点在哪个位置
    (width,height)是矩形的宽度高度
    */
    // 普通的矩形 (bezierPathWithRect:)
    UIBezierPath *path = [UIBezierPath bezierPathWithRect:CGRectMake(50, 50, 200, 200)];
    
    //圆角矩形 (bezierPathWithRoundedRect:cornerRadius:)
    //cornerRadius:圆角半径
    UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50, 50, 200, 200) cornerRadius:100];

    //单独设置某一角的圆角(bezierPathWithRoundedRect:byRoundingCorners:cornerRadius:)
    UIBezierPath * path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(50, 50, 200, 100) byRoundingCorners:UIRectCornerTopLeft cornerRadius:CGSizeMake(10, 20)];    

    //设置线段的颜色
    [[UIColor yellowColor] set];
    //3.把路径添加到上下文
    CGContextAddPath(ctx, path.CGPath);
    //4.把上下文的内容渲染View的layer
    CGContextFillPath(ctx);
}

椭圆形的绘制

    //画椭圆形 bezierPathWithOvalInRect:
    //1.获取上下文
    CGContextRef ctf = UIGraphicsGetCurrentContext();
    //2.描述路径
    UIBezierPath * path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(50, 50, 200, 100)];
    //3.把路径添加到上下文
    CGContextAddPath(ctf, path.CGPath);
    //4.把上下文的内容渲染View的layer
    CGContextStrokePath(ctf);

弧形的绘制

//画弧
-(void)drawRect:(CGRect)rect
{
    //Center:圆心
    //radius:半径
    //startAngle:开始角度,0度在圆的最右侧.往下,角度为正,往上,角度为负
    //endAngle:截至角度
    //clockwise:是否为顺时针方向
    CGPoint center = CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5);
    
    CGFloat radius = rect.size.width * 0.5 - 10;
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0 endAngle:-M_PI_2 clockwise:NO];
    
    [path stroke];   
}

扇形的绘制

  • 绘制空心扇形
//先绘制一个弧形
    //设置弧形的中心点
    CGPoint center = CGPointMake(self.bounds.size.width * 0.5, rect.size.height * 0.5);
    //设置弧形的半径
    CGFloat radius = rect.size.width * 0.5 - 10;
    //绘制弧形曲线
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0 endAngle:-M_PI_2 clockwise:NO];
//绘制扇形
    //添加一根线到圆心
    [path addLineToPoint:center];
    [[UIColor redColor] set];
    //关闭路径(自动从终点连接一根线到起点.)
    [path closePath];
    //渲染到view的layer上
    [path stroke];
  • 绘制实心扇形
    • 通过[path fill],这个填充方法会自动将路径关闭,并填充图形内部分
//先绘制一个弧形
    //设置弧形的中心点
    CGPoint center = CGPointMake(self.bounds.size.width * 0.5, rect.size.height * 0.5);
    //设置弧形的半径
    CGFloat radius = rect.size.width * 0.5 - 10;
    //绘制弧形曲线
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0 endAngle:-M_PI_2 clockwise:NO];
//绘制扇形
    //添加一根线到圆心
    [path addLineToPoint:center];
    [[UIColor redColor] set];
    //填充模式会自动关闭路径
    [path fill];

图形的绘制以及渲染的方式

  • 1.通过获取图形上下文的方式,拼接路径,将路径添加到上下文,将上下文的内容渲染到View的Layer中
```
以弧形绘制的代码为例:
// 1.获取上下文
CGContextRef ctf = UIGraphicsGetCurrentContext();
// 2.绘制路径
UIBezierPath * path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.bounds.size.width * 0.5, self.bounds.size.width * 0.5) radius:100 startAngle:0 endAngle:M_PI clockwise:YES];
// 3.将路径添加到上下文
CGContextAddPath(ctf, path.CGPath);
// 4.将上下文中的内容渲染到View的Layer上
CGContextStrokePath(ctf);
```
  • 2.通过UIKit封装的方法进行上下文的画图
    直接来个: [path stroke];或者[path fill];就可以了.
    它底层的实现,就是获取上下文,拼接路径,把路径添加到上下文,渲染到View
    //绘制路径
    CGPoint center = CGPointMake(rect.size.width * 0.5, rect.size.height * 0.5); 
    CGFloat radius = rect.size.width * 0.5 - 10;
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:center radius:radius startAngle:0 endAngle:-M_PI_2 clockwise:NO];
    //渲染到view的layer上
    [path stroke];
    

绘制文字

  • 1.使用UIKit提供的方法进行绘制.
    方法说明:
    1. drawAtPoint:要画到哪个位置
    withAttributes:文本的样式.
    [str drawAtPoint:CGPointZero withAttributes:nil];

    2.  drawInRect:要将文字绘制到哪个区域
    withAttributes:文本的样式.
    [str drawInRect:rect withAttributes:nil];
    
  • 2.drawAtPoint:和drawInRect:的区别?
    drawAtPoint:不能够自动换行
    drawInRect:能够自动换行

    //1.设置要绘制的文字
    NSString * str = @"绘制文字练习绘制文字练习绘制文字练习绘制文字练习绘制文字练习";

    //2.设置文字的属性,通过Attribute设置
    NSMutableDictionary * dict = [[NSMutableDictionary alloc] init];
    //设置文字字体
    dict[NSFontAttributeName] = [UIFont systemFontOfSize:45];
    //设置文字颜色
    dict[NSForegroundColorAttributeName] = [UIColor yellowColor];
    //设置文字边的宽度
    dict[NSStrokeWidthAttributeName] = @5;
    //设置文字的描边
    dict[NSStrokeColorAttributeName] = [UIColor greenColor];
    //设置文字的阴影
    NSShadow * shadow = [[NSShadow alloc] init];
    shadow.shadowColor = [UIColor cyanColor];
    shadow.shadowOffset = CGSizeMake(10, 10);
    shadow.shadowBlurRadius = 10;
    dict[NSShadowAttributeName] = shadow;

    //3.将文字绘制到当前view 的layer上
    [str drawAtPoint:CGPointZero withAttributes:nil];
    [str drawInRect:rect withAttributes:dict];

绘制图片

绘制图片同样开始要先把图片素材导入.

  • 1.使用UIKit提供的方法进行绘制.
    方法说明:
    1. drawAtPoint:要画到哪个位置
    AtPoint:参数说明图片要绘制到哪个位置.
    通过调用UIKit的方法drawAtPoint:CGPointZero方法进行绘制;
    [str drawAtPoint:CGPointZero];

    2.  drawInRect:要将图片绘制到哪个区域
    AtPoint:参数说明图片要绘制到哪块区域.
    [str drawInRect:rect];
    
  • 在绘制图片过程当中.drawAtPoint:和drawInRect:两个方法的区别?
    drawAtPoint:绘制出来的图图片跟图片的实际尺寸一样大
    drawInRect:使用这个方法绘制出来的图片尺寸会和传入的rect区域一样大.

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

    //会把超过裁剪区域以外的内容给裁剪掉/必须得要在绘制之前设置裁剪区域
    UIRectClip(CGRectMake(0, 0, 50, 50));

    //drawAtPoint:绘制的是原始图片的尺寸大小.
    [image drawAtPoint:CGPointZero];
    //把绘制的图片填充到给的区域当中.
    [image drawInRect:rect];

    //平铺
    [image drawAsPatternInRect:rect];

    [[UIColor redColor] set];
    //快速填充一个区域
    UIRectFill(CGRectMake(50, 50, 100, 100));

模拟系统的UIImageView

  • 实现步骤
    1.自定义一个UIView
    2.定义一个UIImage公共的属性,用于接收外界传递的图片
    3.重写图片属性的set方法,每次传入图片后,进行重绘
    4.定义一个带有image参数的构造方法,在实现构造方法的时候,将view的size设置为image的size,并将image赋值给image属性,这样显示的 view就有了尺寸,并且尺寸和图片的尺寸相同
    5.在drawRect方法中,将外界传入的图片绘制到当前view的Layer上
#import <UIKit/UIKit.h>
@interface ZHJImageView : UIView

//用于接收外界传入的图片
@property (nonatomic, strong) UIImage * image;
//在初始化View的时候,将view的尺寸设置为传入的image的尺寸
-(instancetype)initWithImage:(UIImage *)image;

@end
@implementation ZHJImageView

//当image属性接收到传入的图片的时候,立刻调用drawRect方法,进行重绘
-(void)setImage:(UIImage *)image
{
    _image = image;
//重绘
    [self setNeedsDisplay];
}

//初始化的时候,让当前view的尺寸等于传入的图片的尺寸
-(instancetype)initWithImage:(UIImage *)image{
    if (self = [super init]) {
        //将图片赋值给image属性,并在属性的set方法中重绘
        _image = image;
        self.frame = CGRectMake(0, 0, self.image.size.width, self.image.size.height);
    }
    return self;
}

//将传入的图片绘制到view的layer上
-(void)drawRect:(CGRect)rect
{
    [self.image drawInRect:rect];
}

@end

CADisplayLink的使用(雪花飘落)

  • 在重绘时,NSTimer和CADisplayLink的区别
    setNeedsDisplay底层会调用DrawRect方法重绘.
    但是它不是立马就进行重绘.它仅仅是设置了一个重绘标志,等到下一次屏幕刷新(屏幕的刷新次数是每分钟60次)的时候才会调用DrawRect方法.

    如果使用NSTime的话,假设是0.01调用一次重绘.假设屏幕0.02秒的时候它才刷新一次.中间就会等0.01秒.
    也就是每次都会等0.01秒这样累加上去.让变的越来越卡顿.
    
    使用CADisplayLink的话,它的定时器方法就是屏幕每次刷新的时候就会调用(通常屏幕一秒钟刷新60次)
    它和setNeedsDisplay调用DrawRect方法的时机正好吻合,不会出间等待间隔.不会出现屏幕卡顿现象.
    
#import "SnowFlowView.h"
@implementation SnowFlowView
//因为这个view是从storyboard中加载的,所以将添加子控件的代码写在awakeFromNib中
-(void)awakeFromNib
{
    //创建定时器
    CADisplayLink * link = [CADisplayLink displayLinkWithTarget:self selector:@selector(flowSnow)];
    //将定时器加入到主线程中
    [link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
}

//定义另个静态全局变量,用于保存图片位置
static int snowX = 0;
static int snowY = 0;
//定时器方法
-(void)flowSnow{
    //实现雪花下落的效果
    snowX += 1;
    if (snowX >= [UIScreen mainScreen].bounds.size.width) {
        snowX = 0;
    }
    snowY += 10;
    if (snowY >= [UIScreen mainScreen].bounds.size.height) {
        snowY = 0;
    }
    //重绘
    [self setNeedsDisplay];
}

//将雪花图片绘制到当前的view上
-(void)drawRect:(CGRect)rect
{
    UIImage * image = [UIImage imageNamed:@"雪花"];
    [image drawAtPoint:CGPointMake(snowX, snowY)];
}
@end

图形上下文状态栈

  • 我们获取的图层上下文当中其实有两块区域
    一个是存放添加的路径
    一个是用来保存用户设置的状态,这些状态包括线条的颜色,线宽等.
    当我们把上下文的内容渲染到View上面的时候,它会自动将设置的所有上下文状态运行到保存的路径上面显示到View上面.

  • 上下文状态栈
    上下文状态栈为内存中的一块区域,它用来保存当前上下文的状态,这里所谓的上下文的状态,其实就是在上下文中设置的线条的颜色,宽度等,当再次去出上下文的状态的时候,也就是取出了当时上下文中设置的线宽,颜色等属性给新绘制的线段使用

  • 如何存储和获取图形上下文的状态

    • 1.把上下文状态保存到上下文状态栈
      CGContextSaveGState(ctx);
    • 2.从上下文状态栈中取出上下文状态
      CGContextRestoreGState(ctx);
  • 图形上下文栈使用的示例

-(void)drawRect:(CGRect)rect
{
    //绘制第一条线
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    UIBezierPath * path = [[UIBezierPath alloc] init];
    [path moveToPoint:CGPointMake(20, 150)];
    [path addLineToPoint:CGPointMake(280, 150)];
    
    //第一次设置图形上下文的状态
    CGContextSetLineWidth(ctx, 10);
    [[UIColor cyanColor] set];
    CGContextSaveGState(ctx);//保存第一次设置的上下文的状态
    
    //第二次设置图形上下文的状态
    CGContextSetLineWidth(ctx, 5);
    [[UIColor greenColor] set];
    CGContextSaveGState(ctx);//保存第二次设置的上下文的状态
    
    //渲染第一次绘制的路径
    CGContextAddPath(ctx, path.CGPath);
    CGContextStrokePath(ctx);
    
    //绘制第二条线
    UIBezierPath * path1 = [[UIBezierPath alloc] init];
    [path1 moveToPoint:CGPointMake(150, 20)];
    [path1 addLineToPoint:CGPointMake(150, 280)];
    
    //从位图上下文状态栈中取出位图上下文的状态(取出第一次保存的位图上下文的状态)
    CGContextRestoreGState(ctx);//取出第二次图形上下文的状态
    CGContextRestoreGState(ctx);//取出第一次图像上下文的状态
    
    //渲染第二次绘制的路径
    CGContextAddPath(ctx, path1.CGPath);
    CGContextStrokePath(ctx);
}

图形上下文矩阵的操作(对上下文的路径进行的一些操作,如平移、旋转、缩放)

  • 使用注意点:
    1.想要做上下文的形变操作必须得获取上下文.
    2.形变操作要在添加路径之前进行.
    3.旋转不是以绘制的图形的中心旋转(有可能是以获取的上下文的左上角为原点进行旋转的,通过"CGContextRotateCTM(ctx, M_PI_4);"代码可以发现,旋转的是获取的图形上下文)
- (void)drawRect:(CGRect)rect {
    //获取当前的上下文.
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    //画一个椭圆
    UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(-100, -50, 200, 100)];

    //上下文的矩阵操作,就是可以上下文当中的路径进行一些形变操作.
    //平移操作
    CGContextTranslateCTM(ctx, 100, 50);
    //缩放操作
    CGContextScaleCTM(ctx, 0.5, 0.5);
    //旋转操作
    CGContextRotateCTM(ctx, M_PI_4);
   
    //注意形变操作要在添加路径之前进行.
    [[UIColor redColor]set];
    //把路径添加到上下文.
    CGContextAddPath(ctx, path.CGPath);
    //把上下文的内容渲染到View.
    CGContextFillPath(ctx);  
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 197,966评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,170评论 2 375
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 144,909评论 0 327
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,959评论 1 268
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,851评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,583评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,956评论 3 388
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,590评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,878评论 1 293
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,892评论 2 314
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,719评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,501评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,957评论 3 300
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,124评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,440评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,003评论 2 343
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,211评论 2 339

推荐阅读更多精彩内容

  • Quartz2D以及drawRect的重绘机制字数1487 阅读21 评论1 喜欢1一、什么是Quartz2D Q...
    PurpleWind阅读 757评论 0 3
  • 简述: 1、Quartz2D是什么Quartz2D是二维绘图引擎,同时支持IOS和Mac 2、Quartz2D能做...
    LitterL阅读 632评论 0 6
  • Quartz2D 简介 Quartz2D是二维(平面)的绘图引擎(经包装的函数库,方便开发者使用。也就是说苹果帮我...
    iOS_Cqlee阅读 624评论 0 2
  • Quartz2D 简介及用途 Quartz 2D 是一个二维绘图引擎,同时支持iOS和Mac系统,Quartz2D...
    45b645c5912e阅读 954评论 1 16
  • 介绍: 1.什么是Quartz2D? 他是一个二维的绘图引擎,同时支持iOS和Mac系统 2.Quartz2D能完...
    木木小林酱阅读 999评论 2 3