iOS CoreGraphics 框架介绍

UIBezierPath是CoreGraphics的封装,使用它可以完成大部分的绘图操作,不过更底层的CoreGraphics更加强大。

CoreGraphics,也称为Quartz 2D 是UIKit下的主要绘图系统,频繁的用于绘制自定义视图。Core Graphics是高度集成于UIView和其他UIKit部分的。Core Graphics数据结构和函数可以通过前缀CG来识别。

由于像素是依赖于目标的,所以2D绘图并不能操作单独的像素,我们可以从上下文(Context)读取它。所以我们在绘制之前需要通过

CGContextRef ctx = UIGraphicsGetCurrentContext()

获取当前推入堆栈的图形,相当于你所要绘制图形的图纸,然后绘图就好比在画布上拿着画笔机械的进行画画,通过制定不同的参数来进行不同的绘制。

画完之后我们需要通过

CGContextSetFillColorWithColor(CGContextRef c, CGColorRef color)

CGContextFillPath(CGContextRef c)

来填充颜色并完成最后的绘制。下面我们来完成和UIBezierPath一样的绘制。

1.绘制矩形

绘制矩形需要先定义矩形的rect,然后使用

CGContextAddRect(CGContextRef c, CGRect rect)

进行绘制即可。如下:

- (void)drawRectangle {
    CGRect rectangle = CGRectMake(80, 400, 160, 60);
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    CGContextAddRect(ctx, rectangle);
    CGContextSetFillColorWithColor(ctx, [UIColor lightGrayColor].CGColor);

    CGContextFillPath(ctx);
}

如下:


2.圆和椭圆

我们使用下面这个方法来绘制弧线:

CGContextAddArc(CGContextRef c, CGFloat x, CGFloat y, CGFloat radius, CGFloat startAngle, CGFloat endAngle, int clockwise)

其中的参数说明如下:

c           当前图形
x           圆弧的中心点坐标x
y           曲线控制点的y坐标
radius      指定点的x坐标值
startAngle  弧的起点与正X轴的夹角,
endAngle    弧的终点与正X轴的夹角
clockwise   指定1创建一个顺时针的圆弧,或是指定0创建一个逆时针圆弧

所以我们可以通过下面创建圆形:

- (void)drawCircleAtX:(float)x Y:(float)y {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextAddArc(ctx, x, y, 150, 0, 2 * M_PI, 1);
    CGContextSetFillColorWithColor(ctx, [UIColor blackColor].CGColor);
    CGContextFillPath(ctx);
}

现在看起来:

屏幕快照 2015-03-14 上午12.10.07.png
屏幕快照 2015-03-14 上午12.10.07.png

绘制椭圆我们需要先给定一个容纳椭圆的矩形,然后使用

CGContextAddEllipseInRect(CGContextRef context, CGRect rect)

进行绘制,如下:

- (void)drawEllipseAtX:(float)x Y:(float)y {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGRect rectangle = CGRectMake(x, y, 60, 30);
    CGContextAddEllipseInRect(ctx, rectangle);
    CGContextSetFillColorWithColor(ctx, [UIColor redColor].CGColor);
    CGContextFillPath(ctx);
}

现在看起来:


3.多边形

绘制多边形需要通过CGContextMoveToPoint从一个开始点开始一个新的子路径,然后通过CGContextAddLineToPoint在当前点追加直线段,最后通过CGContextClosePath关闭路径即可。如下我们绘制一个三角形:

- (void)drawTriangle {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextBeginPath(ctx);

    CGContextMoveToPoint(ctx, 160, 40);
    CGContextAddLineToPoint(ctx, 190, 80);
    CGContextAddLineToPoint(ctx, 130, 80);
    CGContextClosePath(ctx);

    CGContextSetFillColorWithColor(ctx, [UIColor blackColor].CGColor);
    CGContextFillPath(ctx);
}

现在看起来:

屏幕快照 2015-03-14 上午12.18.00.png
屏幕快照 2015-03-14 上午12.18.00.png

4.不规则形状

1).绘制一段弧度:[self drawCurve];
a).第一种:和贝塞尔曲线中的第一种一样,我们同样需要给定起始点
CGContextMoveToPoint(CGContextRef c, CGFloat x, CGFloat y)

给定控制点和终点:

CGContextAddQuadCurveToPoint(CGContextRef c, CGFloat cpx, CGFloat cpy, CGFloat x, CGFloat y)

其中:

cpx: 曲线控制点的x坐标
cpy: 曲线控制点的y坐标
- (void)drawQuadCurve {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextBeginPath(ctx);

    CGContextMoveToPoint(ctx, 50, 130);
    CGContextAddQuadCurveToPoint(ctx, 0, 100, 25, 170);

    CGContextSetLineWidth(ctx, 10);
    CGContextSetStrokeColorWithColor(ctx, [UIColor brownColor].CGColor);
    CGContextStrokePath(ctx);
}

我们画两个如上的曲线,现在看起来:


b).第二种:

第二种我们需要给两个控制点:

- (void)drawCurve2{
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextBeginPath(ctx);

    CGContextMoveToPoint(ctx, 170, 170);
    CGContextAddCurveToPoint(ctx, 160, 250, 230, 250, 160, 290);

    CGContextSetLineWidth(ctx, 10);
    CGContextSetStrokeColorWithColor(ctx, [UIColor brownColor].CGColor);
    CGContextStrokePath(ctx);    
}

现在看起来:


还不错。

5.加阴影效果

可以通过

CGContextSetShadowWithColor(CGContextRef context, CGSize offset, CGFloat blur, CGColorRef color)

设置阴影效果,4个参数分别是图形上下文,偏移量(CGSize),模糊值,和阴影颜色。我们在画圆圈的方法中加入它:

- (void)drawCircleAtX:(float)x Y:(float)y {
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextAddArc(ctx, x, y, 150, 0, 2 * M_PI, 1);
    CGContextSetShadowWithColor(ctx, CGSizeMake(10, 10), 20.0f, [[UIColor grayColor] CGColor]);
    CGContextSetFillColorWithColor(ctx, [UIColor yellowColor].CGColor);
    CGContextFillPath(ctx);
}

注意,它除了会在会在边缘绘制阴影效果,还会在有子控件的地方绘制,如下:


6.渐变色效果
1)放射式渐变:CGContextDrawRadialGradient

放射式渐变以某种颜色从一点开始,以另一种颜色在其它点结束。它看起来会是一个圆。

为了创建一个放射式渐变,你要调用CGGradientCreateWithColors函数。这个函数的返回值是一个新的类型为CGGradientRef的渐变。

CGGradientCreateWithColors包含以下3个参数:

Color Space:这是一个色彩范围的容器,类型是CGColorSpaceRef. 这个参数,我们可以传入CGColorSpaceCreateDeviceRGB函数的返回值,它将给我们一个RGB色彩空间。
颜色分量的数组:这个数组必须包含颜色的数组值。
位置数组:颜色数组中各个颜色的位置,此参数控制该渐变从一种颜色过渡到另一种颜色的速度有多快。

如下:

- (void)drawdrawRadialGradientWithRect:(CGRect)rect
{
//先创造一个CGGradientRef,颜色是白,黑,location分别是0,1
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    NSArray* gradientColors = [NSArray arrayWithObjects:
                               (id)[UIColor whiteColor].CGColor,
                               (id)[UIColor blackColor].CGColor, nil];
    CGFloat gradientLocations[] = {0, 1};

    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace,
                                                        (__bridge CFArrayRef)gradientColors,
                                                        gradientLocations);
    CGPoint startCenter = CGPointMake(CGRectGetMidX(rect), CGRectGetMidY(rect));
    CGFloat radius = MAX(CGRectGetHeight(rect), CGRectGetWidth(rect));

调用完上面那个函数后,我们需要使用:

CGContextDrawRadialGradient(CGContextRef context, CGGradientRef gradient, CGPoint startCenter, CGFloat startRadius, CGPoint endCenter, CGFloat endRadius, CGGradientDrawingOptions options)

进行上下文绘制,参数说明如下:

CGPoint startCenter:白色的起点(中心圆点)
CGFloat startRadius:起点的半径,这个值多大,中心就是多大一块纯色的白圈
CGPoint endCenter:白色的终点, 可以和起点一样,不一样的话就像探照灯一样从起点投影到这个终点
CGFloat endRadius:终点的半径,

如下:

CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextDrawRadialGradient(context, gradient,
                                startCenter, 0,
                                startCenter, radius,
                                0);

    CGGradientRelease(gradient);
    CGColorSpaceRelease(colorSpace);
}

我们这样调用它:

[self drawdrawRadialGradientWithRect:CGRectMake(120, 510, 60, 60)];

效果如下;


2)线性渐变:CGGradientCreateWithColorComponents

线性渐变以某种颜色从一点开始,以另一种颜色在其它点结束。

你先要调用上面讲到的drawdrawRadialGradientWithRect 函数去创建一个gradient渐变,创建好gradient后,我们将使用

CGContextDrawLinearGradient(CGContextRef context, CGGradientRef gradient, CGPoint startPoint, CGPoint endPoint, CGGradientDrawingOptions options)

在图形上下文中绘制,此过程需要五个参数, 比上面的辐射渐变多了最后一个参数:

Gradient drawing options :指定当你的起点或者终点不在图形上下文的边缘内时该如何处理。你可以使用你的开始或结束颜色来填充渐变以外的空间。此参数为以下值之一:
KCGGradientDrawsAfterEndLocation扩展整个渐变到渐变的终点之后的所有点, KCGGradientDrawsBeforeStartLocation扩展整个渐变到渐变的起点之前的所有点。
0不扩展该渐变。

代码如下:

- (void)drawingLinearGradientWithStartPoint:(CGPoint)startPoint endPoint:(CGPoint)endPoint
{
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    NSArray* gradientColors = [NSArray arrayWithObjects:
                               (id)[UIColor whiteColor].CGColor,
                               (id)[UIColor purpleColor].CGColor, nil];
    CGFloat gradientLocations[] = {0, 1};

    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace,
                                                        (__bridge CFArrayRef)gradientColors,
                                                        gradientLocations);

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
    CGContextDrawLinearGradient(context, gradient, startPoint, endPoint,0);
    CGContextRestoreGState(context);
    CGGradientRelease(gradient);
    CGColorSpaceRelease(colorSpace);
}

效果如下:


你也可以用一个自定义的形状来抱住你创建的渐变,如下所示:

CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    NSArray* gradientColors = [NSArray arrayWithObjects:
                               (id)[UIColor whiteColor].CGColor,
                               (id)[UIColor purpleColor].CGColor, nil];
    CGFloat gradientLocations[] = {0, 1};

    CGGradientRef gradient = CGGradientCreateWithColors(colorSpace,
                                                        (__bridge CFArrayRef)gradientColors,
                                                        gradientLocations);

    CGContextRef context = UIGraphicsGetCurrentContext();
    CGContextSaveGState(context);
    CGContextMoveToPoint(context, 100, 100);
    CGContextAddArc(context, 100, 100, 60, 1.04 , 2.09 , 0);
    CGContextClosePath(context);
    CGContextClip(context);


    CGPoint endshine;
    CGPoint startshine;
    startshine = CGPointMake(100 + 60 * cosf( 1.57 ),100+ 60 * sinf( 1.57 ));
    endshine = CGPointMake(100,100);
    CGContextDrawLinearGradient(context,gradient , startshine, endshine, kCGGradientDrawsAfterEndLocation);
    CGContextRestoreGState(context);

效果如下:


上面除了使用drawdrawRadialGradientWithRect函数外,还可以使用

CGGradientCreateWithColorComponents包含以下4个参数:

Color Space:和上面一样
颜色分量的数组:这个数组必须包含CGFloat类型的红、绿、蓝和alpha值。数组中元素的数量和接下来两个参数密切。从本质来讲,你必须让这个数组包含足够的值,用来指定第四个参数中位置的数量。所以如果你需要两个位置(起点和终点),那么你必须为数组提供两种颜色。
位置数组:颜色数组中各个颜色的位置,此参数控制该渐变从一种颜色过渡到另一种颜色的速度有多快。
位置的数量:这个参数指明了我们需要多少颜色和位置。

例如:

CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, (CGFloat[]){  
        0.8, 0.2, 0.2, 1.0,  
        0.2, 0.8, 0.2, 1.0,  
        0.2, 0.2, 0.8, 1.0  
    }, (CGFloat[]){  
        0.0, 0.5, 1.0  
    }, 3);

3.一些可能需要注意的地方

上面我们将了自定义绘图,相对与它来讲,UIView及其子类是高度优化的,所以在能用UIView解决的地方,尽量不要使用自定义绘图,最快的绘图方式就是根本不绘制(废话=_=),iOS在尽量避免调用drawRect:方法,使用一个合适的contentMode方法,系统在旋转或重新调整大小时就不需要调用drawRect:方法,导致drawRect:方法运行的最常见情况是调用了setNeedDisplay。



文/庄洁元(简书作者)
原文链接:http://www.jianshu.com/p/521a11919d5e
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值