CoreGraphics(转)
2.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);
}
现在看起来:
绘制椭圆我们需要先给定一个容纳椭圆的矩形,然后使用
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);
}
现在看起来:
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。
你可以在这里下载到本文的代码。
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/css/cuteeditor.css);
CoreGraphics(转)的更多相关文章
- iOS开发CoreGraphics核心图形框架之一——CGPath的应用
一.引言 CoreGraphics核心图形框架相较于UIKit框架更加偏于底层.在Objective-C工程中,CoreGraphics其中方法都是采用C语言风格进行编写的,同时其并不支持Obj ...
- Quartz2D 编程指南(四)位图与图像遮罩、CoreGraphics 绘制 Layer
概览 图形上下文 路径 颜色与颜色空间 变换 图案 阴影 渐变 透明层 Quartz 2D 中的数据管理 位图与图像遮罩 CoreGraphics 绘制 Layer 位图与图像遮罩 简介 位图与图像遮 ...
- CoreGraphics QuartzCore CGContextTranslateCTM 用法
原点是: 左下角 旋转: 逆时针 位移: 右上为正, 左下为负 CGContextTranslateCTM CGContextRotateCTM CGContextScaleCTM 而且, 以上几 ...
- iOS开发--CoreGraphics简单绘图
一.导入coreGraphics.framework 二.绘制图形 1.绘制矩形 ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 // 绘制矩形 - (v ...
- CoreGraphics --- 翻转坐标系
1. 由于CoreGraphics 的坐标系与手机屏幕坐标系的Y轴是相反的, 所以在我们开发的时候, 需要翻转坐标系; - (void)drawRect:(CGRect)rect { CGContex ...
- 【转】 CoreGraphics QuartzCore CGContextTranslateCTM 用法
原文:http://blog.csdn.net/sqc3375177/article/details/25708447 CoreGraphics.h 一些常用旋转常量 #define M_E 2.71 ...
- CoreGraphics 之CGAffineTransform仿射变换(3)
CoreGraphics 之CGAffineTransform仿射变换(3) CoreGraphics 的 仿射变换 可以用于 平移.旋转.缩放变换路径 或者图形上下文. (1)平移变换将路径或图 ...
- CoreGraphics QuartzCore CGContextTranslateCTM 说明
CoreGraphics.h 一些经常使用旋转常量 #define M_E 2.71828182845904523536028747135266250 e #define M_LOG2E 1.442 ...
- iOS绘图框架CoreGraphics分析
由于CoreGraphics框架有太多的API,对于初次接触或者对该框架不是十分了解的人,在绘图时,对API的选择会感到有些迷茫,甚至会觉得iOS的图形绘制有些繁琐.因此,本文主要介绍一下iOS的绘图 ...
- iOS 动画篇 (三) CADisplayLink与CoreGraphics实现动画
本文主要介绍利用CoreGraphics和CADisplayLink来实现一个注水动画.来一个效果图先: 在介绍注水动画前,先介绍利用CoreGraphics实现进度条的绘制. 一.扇形进度绘制 效果 ...
随机推荐
- DOM节点太多导致页面卡顿的优化方法
http://developer.51cto.com/art/201504/473422.htm
- Network | router & switch
路由器 A router is a device that forwards data packets between computer networks. This creates an overl ...
- robot upstart 问题
1.启动后在记录文件发现左轮节点未启动: 因为左边的类未实例化,不会去订阅消息然后初始化 2.两个节点均可以启动后,发现启动后又死掉 因为在程序里有getenv(“HOME”)然后付给string,g ...
- Java基础教程:tutorialspoint-junit
教程: 来自turorialspoint的JUnit教程(英文),官网:https://www.tutorialspoint.com/junit/index.htm 中文版本:http://wiki. ...
- 用AntRun插件测试Maven的生命周期
在用AntRun插件之前,需要了解以下几个知识点: 1.Maven的生命周期,参考:http://www.cnblogs.com/EasonJim/p/6816340.html,主要是要知道生命周期里 ...
- 2008 SQL SERVER 用户 架构
2008 SQL SERVER 用户: SERVER用户与数据库用户 SERVER 与 数据库用户的映射,以使 登陆用户可访问数据库 架构等同于SCHEM (表空间),即表空间管理对象,建立层次对象关 ...
- 邁向IT專家成功之路的三十則鐵律 鐵律二十二:IT人升遷之道-無為
升遷管道是許多人求職時相當重要的考量之一,畢竟人除了很愛錢之外更愛顯赫的頭銜,然而在企業中越顯赫的頭銜,其背後通常有更多的罵名,因為許多人的高官厚爵都是踩著一群人的頭頂爬上去的,隨時哪一天跌了下來,都 ...
- 26个高效工作的小技巧 z
1.时间常有,时间优先. 2.时间总会有的:每天只计划4-5 小时真正的工作. 3.当你在状态时,就多干点:不然就好好休息:有时候会连着几天不是工作状态,有时在工作状态时却又能天天忙活 12 小时,这 ...
- 微信小程序日期定位弹出框遮挡问题
只需要用bindtap绑定一个点击后的操作(隐藏键盘): wx.hideKeyboard()
- Gson解析数组和list容器
Gson解析数组和list容器 使用Gson解析首先须要增加架包文件:gson-2.2.4.jar 定义一个类Student: public class Student { String name=& ...