关于ios图形绘制
引言:
Quartz 2D绘图的核心API是CGContextRef,该API专门用于绘制各种图形。Quartz 2D是一个二维图形绘制引擎,它支持iOS环境和Mac OS X环境,为开发者会提供了很多的方便,它在绘图上功能是非常强大的,如 基于路径的绘图、透明度、阴影、颜色管理、反锯齿、PDF文档生成和PDF元数据访问 等。Quartz 2DAPI作为Core Graphics框架的一部分,因此其中的很多数据类型和方法都是以CG开头的。会经常见到Quartz 2D(Quartz)和Core Graphics两个术语交互使用。
GraphicsContext是图形上下文,通常可以理解为一块画布,我们可以在上面进行绘画操作,绘制完成后,将画布放到我们的view中显示即可,view看作是一个画框.CGContextRef功能强大,我们借助它可以很方便的画出各种图形。在开发过程中灵活运用这些绘画技巧,可以帮助我们提升技术水平。
正文:
话不多说,先上图在上代码。
代码:(复制后即可使用)
自定义一个CustomView类,继承UIView
#import "CustomView.h"
#import <QuartzCore/QuartzCore.h>
#define PI 3.14159265358979323846
@implementation CustomView
-(instancetype)initWithFrame:(CGRect)frame{
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor lightGrayColor];
}
return self;
}
// 覆盖drawRect方法,你可以在此自定义绘画和动画
- (void)drawRect:(CGRect)rect
{
//一个不透明类型的Quartz 2D绘画环境,相当于一个画布,你可以在上面任意绘画
CGContextRef context = UIGraphicsGetCurrentContext();
#pragma mark /*1.写文字*/
//设置填充颜色
CGContextSetRGBFillColor (context,255/255.0,175/255.0,40/255.0, 1.0);
//增添字体属性
NSDictionary *mDic = @{NSForegroundColorAttributeName:[UIColor cyanColor],
NSFontAttributeName:[UIFont systemFontOfSize:13]};
[@"画圆:" drawInRect:CGRectMake(10, 20, 80, 20) withAttributes:mDic];
[@"画线及孤线:" drawInRect:CGRectMake(10, 80, 80, 20) withAttributes:mDic];
[@"画矩形:" drawInRect:CGRectMake(10, 130, 80, 20) withAttributes:mDic];
[@"画图形:" drawInRect:CGRectMake(10, 260, 80, 20) withAttributes:mDic];
[@"画贝塞尔曲线:" drawInRect:CGRectMake(10, 350, 80, 20) withAttributes:mDic];
[@"图片:" drawInRect:CGRectMake(10, 400, 80, 20) withAttributes:mDic];
[@"画虚线:" drawInRect:CGRectMake(10, 460, 80, 20) withAttributes:mDic];
#pragma mark /*2.画圆*
//边框圆1
CGContextSetRGBStrokeColor(context,255/255.0,255/255.0,255/255.0,1.0);//画笔线的颜色
CGContextSetLineWidth(context, 1.0);//线的宽度
/*
void CGContextAddArc(CGContextRef c,CGFloat x, CGFloat y,CGFloat radius,CGFloat startAngle,CGFloat endAngle, int clockwise);
参数:x,y为圆点坐标,radius半径,startAngle为开始的角度,endAngle为 结束的角度,clockwise 0为顺时针,1为逆时针。
*/
CGContextAddArc(context, 70, 30, 15, 0, 2*PI, 0); //添加一个圆
CGContextDrawPath(context, kCGPathStroke); //绘制路径
/*
kCGPathFill:只有填充(非零缠绕数填充),不绘制边框
kCGPathEOFill:奇偶规则填充(多条路径交叉时,奇数交叉填充,偶交叉不填充)
kCGPathStroke:只有边框
kCGPathFillStroke:既有边框又有填充(有边框颜色 和 填充颜色)
kCGPathEOFillStroke:奇偶填充并绘制边框
*/
//填充圆2
CGContextSetRGBFillColor (context,255/255.0,175/255.0,40/255.0, 1.0);
CGContextAddArc(context, 130, 30, 20, 0, 2*PI, 0);
CGContextDrawPath(context, kCGPathFill);
//画有边框的实体圆3
UIColor *aColor = [UIColor colorWithRed:1 green:0.0 blue:0 alpha:1];
CGContextSetFillColorWithColor(context, aColor.CGColor);
CGContextSetLineWidth(context, 3.0);//线的宽度
CGContextAddArc(context, 200, 30, 30, 0, PI*2, 0);
CGContextDrawPath(context, kCGPathFillStroke);//绘制路径加填充
#pragma mark /*3.画线及孤线*/
//画线1
CGPoint aPoints[2];//坐标点
aPoints[0] =CGPointMake(120, 80);//坐标1
aPoints[1] =CGPointMake(160, 100);//坐标2
CGContextAddLines(context, aPoints, 2);//points[]坐标数组,count数组大小
CGContextStrokePath(context);//直接写方法 不需要路径绘制参数
//画线2
CGContextSetStrokeColorWithColor(context, [UIColor yellowColor].CGColor);
CGContextMoveToPoint(context, 170, 80);
CGContextAddLineToPoint(context, 170, 100);
CGContextDrawPath(context, kCGPathStroke);
//圆弧1(0到π逆时针的弧线)
CGContextSetLineWidth(context, 2.0);
CGContextSetStrokeColorWithColor(context, [UIColor greenColor].CGColor);
CGContextAddArc(context, 200, 100, 15, 0, M_PI, 1);
CGContextDrawPath(context, kCGPathStroke);
//画笑脸弧线2
//左
CGContextSetRGBStrokeColor(context, 255/255.0,255/255.0,255/255.0,1.0);//改变画笔颜色
CGContextMoveToPoint(context, 240, 90);//开始点坐标p1
//CGContextAddArcToPoint(CGContextRef c, CGFloat x1, CGFloat y1,CGFloat x2, CGFloat y2, CGFloat radius)
//参数:CGFloat x1 控制点的x坐标, CGFloat y1 控制点的y坐标,CGFloat x2 结束点的x坐标, CGFloat y2 结束点的y坐标, CGFloat radius 半径
/*
开始点的坐标为p1,控制点坐标为p2,结束点的的坐标为p3
以p2为端点,发出两条射线,分别经过p1和p3,那么与两条射线相切的圆有无数个,若是给一个确定的半径,则可以确定一个圆。那么函数可以绘制两个切点之间的一段弧线
1).若开始点和结束点正好在两个切点的位置,则绘制一条弧线。
2).若开始点不是切点,则以开始点连一条直线到切点再绘制弧线。
3).所以该函数需要确定好控制点 和 结束点的位置 及 半径的值
4).上下文会自动以结束点为 current point。
*/
CGContextAddArcToPoint(context, 248, 78, 256, 90, 10);
CGContextStrokePath(context);//绘画路径
//右
CGContextMoveToPoint(context, 260, 90);
CGContextAddArcToPoint(context, 268, 78, 276, 90, 10);
CGContextStrokePath(context);
//下
CGContextMoveToPoint(context, 250, 100);
CGContextAddArcToPoint(context, 258, 112, 266, 100, 10);
CGContextStrokePath(context);
//用CGContextMoveToPoint画一个圆角半径为10的矩形
//左
CGContextSetStrokeColorWithColor(context, [UIColor redColor].CGColor);
CGContextMoveToPoint(context, 300, 80);
CGContextAddArcToPoint(context, 300, 120, 310, 120, 10);
CGContextStrokePath(context);
//下
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
CGContextMoveToPoint(context, 310, 120);
CGContextAddArcToPoint(context, 340, 120, 340, 110, 10);
CGContextStrokePath(context);
//右
CGContextMoveToPoint(context, 340, 110);
CGContextAddArcToPoint(context, 340, 70, 330, 70, 10);
CGContextStrokePath(context);
//上
CGContextMoveToPoint(context, 330, 70);
CGContextAddArcToPoint(context, 300, 70, 300, 80, 10);
CGContextStrokePath(context);
#pragma mark /*4.画矩形*/
CGContextSetLineWidth(context, 1);
CGContextSetRGBStrokeColor(context, 1, 1, 1, 1);
CGContextStrokeRect(context,CGRectMake(80, 120, 30, 30));//画方框
CGContextSetLineWidth(context, 2.0);//线的宽度
aColor = [UIColor blueColor];//blue蓝色
CGContextSetFillColorWithColor(context, aColor.CGColor);//填充颜色
aColor = [UIColor yellowColor];
CGContextSetStrokeColorWithColor(context, aColor.CGColor);//线框颜色
CGContextAddRect(context,CGRectMake(140, 120, 60, 30));
CGContextDrawPath(context, kCGPathFillStroke);
//渐变颜色矩形1
//关于颜色参考http://blog.sina.com.cn/s/blog_6ec3c9ce01015v3c.html
//http://blog.csdn.net/reylen/article/details/8622932
//第一种填充方式,第一种方式必须导入类库quartcore并#import <QuartzCore/QuartzCore.h>,这个就不属于在context上画,而是将层插入到view层上面。那么这里就涉及到Quartz Core图层编程了。
CAGradientLayer *gradient1 = [CAGradientLayer layer];
gradient1.frame = CGRectMake(240, 120, 40, 40);
gradient1.colors = [NSArray arrayWithObjects:
(id)[UIColor purpleColor].CGColor,
(id)[UIColor greenColor].CGColor,
(id)[UIColor cyanColor].CGColor,
(id)[UIColor yellowColor].CGColor,
nil];
//注意这几个数字在0到1之间单调递增。
gradient1.locations = [NSArray arrayWithObjects:
[NSNumber numberWithFloat:0.1],
[NSNumber numberWithFloat:0.3],
[NSNumber numberWithFloat:0.6],
[NSNumber numberWithFloat:1.0], nil];
//向量方向 表示颜色层次方向(左上角为(0.0) 右下角为(1.1))
gradient1.startPoint = CGPointMake(1, 0);
gradient1.endPoint = CGPointMake(1, 1);
[self.layer insertSublayer:gradient1 atIndex:0];
//渐变颜色矩形2
//第二种填充方式
CGColorSpaceRef rgb = CGColorSpaceCreateDeviceRGB();
CGFloat colors[] =
{
1,1,1, 1.00,
1,1,0, 1.00,
1,0,0, 1.00,
1,0,1, 1.00,
0,1,1, 1.00,
0,1,0, 1.00,
0,0,1, 1.00,
0,0,0, 1.00,
};
//参数:创建一个渐变的色值 1:颜色空间 2:渐变的色数组 3:位置数组,如果为NULL,则为平均渐变,否则颜色和位置一一对应 4:位置的个数
CGGradientRef gradient = CGGradientCreateWithColorComponents
(rgb, colors, NULL, sizeof(colors)/(sizeof(colors[0])*4));//形成梯形,渐变的效果
//使用RGB模式的颜色空间(在Quartz 2D中凡是使用带有Create或者Copy关键字方法创建的对象,在使用后一定要使用对应的方法释放)
CGColorSpaceRelease(rgb);
//画线形成一个矩形
//CGContextSaveGState 与 CGContextRestoreGState的作用
/*
CGContextSaveGState函数的作用是将当前图形状态推入堆栈。之后,您对图形状态所做的修改会影响随后的描画操作,但不影响存储在堆栈中的拷贝。在修改完成后,您可以通过CGContextRestoreGState函数把堆栈顶部的状态弹出,返回到之前的图形状态。这种推入和弹出的方式是回到之前图形状态的快速方法,避免逐个撤消所有的状态修改。这也是将某些状态(比如裁剪路径)恢复到原有设置的唯一方式。
举个例子:现在画一个矩形框,边框的宽度为1,颜色为红色 save上下文,接着再画一个矩形框,宽度为2,颜色为蓝色。若现在又想画另一个宽度为1,颜色为红色的矩形,就不必改去写CGContextSetLineWidth()和CGContextSetFillColorWithColor()函数改变属性了,直接restore上下文,上下文就恢复到save之前的各项属性了,省去了重复更改上下文属性的代码编写了。
*/
CGContextSaveGState(context);
CGContextMoveToPoint(context, 320, 130);
CGContextAddLineToPoint(context, 350, 130);
CGContextAddLineToPoint(context, 350, 160);
CGContextAddLineToPoint(context, 320, 160);
//context裁剪路径,后续操作的路径
CGContextClip(context);
//CGContextDrawLinearGradient(CGContextRef context,CGGradientRef gradient, CGPoint startPoint, CGPoint endPoint,CGGradientDrawingOptions options)
//参数:gradient渐变颜色,startPoint开始渐变的起始位置,endPoint结束坐标,options开始坐标之前or开始之后开始渐变
CGContextDrawLinearGradient(context, gradient,CGPointMake
(320,130) ,CGPointMake(350,130),
kCGGradientDrawsAfterEndLocation);
CGContextRestoreGState(context); //恢复到之前的context
//下面再看一个颜色渐变的圆
/*CGContextDrawRadialGradient(CGContextRef _Nullable c, CGGradientRef _Nullable gradient, CGPoint startCenter, CGFloat startRadius, CGPoint endCenter, CGFloat endRadius, CGGradientDrawingOptions options)
参数介绍:
startCenter:起始点 startRadius:起始点的半径 endCenter:终止点 endRadius: 终止点的半径 GGradientDrawingOptions options: 扩展
options: 当你的起点或者终点不在图形上下文的边缘内时,指定该如何处理。你可以使用你的开始或结束颜色来填充渐变以外的空间。此参数为以下值之一:KCGGradientDrawsAfterEndLocation扩展整个渐变到渐变的终点之后的所有点 KCGGradientDrawsBeforeStartLocation扩展整个渐变到渐变的起点之前的所有点。0不扩展该渐变。
kCGGradientDrawsBeforeStartLocation
kCGGradientDrawsAfterEndLocation
*/
CGContextDrawRadialGradient(context, gradient, CGPointMake(90, 200), 0, CGPointMake(90, 200), 20, 0);
//渐变圆筒
CGPoint ZHstart = CGPointMake(170, 200);//起始点
CGPoint ZHend = CGPointMake(250, 200); //终结点
CGContextDrawRadialGradient(context, gradient, ZHstart, 5, ZHend, 30, 0);//可以试试改变最后一个参数看看效果
#pragma mark /*5.画扇形和椭圆*/
//画扇形,也就画圆,只不过是设置角度的大小,形成一个扇形
aColor = [UIColor colorWithRed:0 green:1 blue:1 alpha:1];
CGContextSetFillColorWithColor(context, aColor.CGColor);//填充颜色
CGContextSetRGBStrokeColor(context, 1, 1, 1, 1);
//以10为半径围绕圆心画指定角度扇形
CGContextMoveToPoint(context, 100, 290);
CGContextAddArc(context, 100, 290, 30, -60 * PI / 180, -120 * PI / 180, 1);
CGContextClosePath(context);//闭合图形
CGContextDrawPath(context, kCGPathFillStroke);
//画椭圆
CGContextAddEllipseInRect(context, CGRectMake(130, 260, 40, 20));
CGContextDrawPath(context, kCGPathFillStroke);
#pragma mark /*6.画多边形*/
//只要三个点就行跟画一条线方式一样,把三点连接起来
CGPoint sPoints[3]; //坐标点
sPoints[0] = CGPointMake(180, 290);//坐标1
sPoints[1] = CGPointMake(210, 290);//坐标2
sPoints[2] = CGPointMake(240, 230);//坐标3
CGContextAddLines(context, sPoints, 3);//添加线
CGContextClosePath(context);//封起来
CGContextDrawPath(context, kCGPathFillStroke); //根据坐标绘制路径
//不规则五边形
CGPoint myPoints[5]; //坐标点
myPoints[0] = CGPointMake(250, 300);//坐标1
myPoints[1] = CGPointMake(280, 300);//坐标2
myPoints[2] = CGPointMake(280, 240);//坐标3
myPoints[3] = CGPointMake(250, 240);//坐标4
myPoints[4] = CGPointMake(265, 270);//坐标5
CGContextAddLines(context, myPoints, 5);//添加线
CGContextClosePath(context);//封起来
CGContextDrawPath(context, kCGPathFillStroke); //根据坐标绘制路径
//使用贝塞尔画五角星 (此处不详细讲贝塞尔的使用)
UIBezierPath* starPath = UIBezierPath.bezierPath;
[starPath moveToPoint: CGPointMake(314.5, 241)];
[starPath addLineToPoint: CGPointMake(326.31, 255.41)];
[starPath addLineToPoint: CGPointMake(346.36, 260.35)];
[starPath addLineToPoint: CGPointMake(333.62, 274.19)];
[starPath addLineToPoint: CGPointMake(334.19, 291.65)];
[starPath addLineToPoint: CGPointMake(314.5, 285.8)];
[starPath addLineToPoint: CGPointMake(294.81, 291.65)];
[starPath addLineToPoint: CGPointMake(295.38, 274.19)];
[starPath addLineToPoint: CGPointMake(282.64, 260.35)];
[starPath addLineToPoint: CGPointMake(302.69, 255.41)];
[starPath closePath];//封闭
[[UIColor cyanColor] setFill];
[starPath fill];//填充颜色
#pragma mark /*7.画贝塞尔曲线*/
//二次曲线
CGContextMoveToPoint(context, 120, 350);//设起点
//设置贝塞尔曲线的控制点坐标和终点坐标
CGContextAddQuadCurveToPoint(context,150, 305, 180, 350);
CGContextStrokePath(context);
//三次曲线函数(控制点1,控制点2,终点)
CGContextMoveToPoint(context, 200, 350);//设起点
CGContextAddCurveToPoint(context,250, 330, 220, 400, 280, 320);
CGContextStrokePath(context);
#pragma mark /*8.图片*/
UIImage *image = [UIImage imageNamed:@"wo.jpg"];
[image drawInRect:CGRectMake(60, 400, 60, 60)];
CGContextDrawImage(context, CGRectMake(160, 400, 60, 60), image.CGImage);
//[image drawAtPoint:CGPointMake(200, 430)];//保持图片原始大小
//平铺图
//CGContextDrawTiledImage(context, CGRectMake(160, 400, 30, 30), image.CGImage);
#pragma mark /*9.画虚线*/
CGContextSetLineWidth(context, 4.0);
CGContextSetStrokeColorWithColor(context, [UIColor whiteColor].CGColor);
//lengths的值{10,10}表示先绘制10个点的长度,再跳过10个点的长度,如此反复
CGFloat lengths[] = {10,10};
//注意:如果对上下文进行了修改之后的所有连线的类型都默认为虚线啦!其他属性也一并如此。
//设置线条起点和终点的样式为圆角
CGContextSetLineCap(context, kCGLineCapRound);
/*
CGContextSetLineDash(CGContextRef _Nullable c, CGFloat phase, const CGFloat * _Nullable lengths, size_t count);
参数:
CGFloat phase:绘制第一个虚线点时先减去该数值的长度。
size_t count:必须和lengths数组长度匹配。
*/
CGContextSetLineDash(context, 5, lengths,2);
CGContextMoveToPoint(context, 0, 490);
CGContextAddLineToPoint(context, self.frame.size.width-3,520);
CGContextStrokePath(context);
CGContextSetLineWidth(context, 2.0);
CGFloat lengths1 [] = {10,10,5};//第一个数为实线长,第二个为空隙长度,第三个实线长度,第四个空隙长度,三个数一直循环
CGContextSetLineDash(context, 0, lengths1,3);
CGContextMoveToPoint(context, 0, 530);
CGContextAddLineToPoint(context, self.frame.size.width,530);
CGContextStrokePath(context);
}
@end
声明:
本文由作者参考或学习后花费一定的时间和精力所攒写,若要转载请注明出处,尊重作者的劳动成果,希望大家共同分享,共同学习,共同提升!
原文地址:https://blog.csdn.net/qq_36059034/article/details/60874582