当前位置:   article > 正文

iOS - Quart2D绘图之UIGraphicsBeginImageContextWithOptions基础_ios uigraphicsbeginimagecontextwithoptions

ios uigraphicsbeginimagecontextwithoptions

背景:

某天,你正在上班ing……这个时候老大过来了,“小王啊,这个按钮太丑了,客户要求变成五角星形状的,UI没空给你切图,你给我完成这个需求啊”,说完便头也不回的走了,留下你一个人在冷风中摇曳,心里一万只草泥马在狂奔……


1.png

OK OK ,自己选的IOS开发,哭着也要完成…… 这里你可能就需要使用绘图这一块的知识了。如果你恰好这块还是比较空白的,那么就是。。。


2.gif

.
.
.

没关系,先让我们重drawRect,这个方法开始吧。
首先了解一下这个东西干嘛的,怎么用,啥时候用。

  • 1 干嘛的:如果你要对View进行绘制,那么你就要到这里处理
  • 2 怎么用:那当然是在这里涂鸦
  • 3 啥时候用:代码说明一切
    1. -[DrawLineViewcontroller loadView]
    2. -[DrawLineViewcontroller viewDidLoad]
    3. -[DrawLineViewcontroller viewWillAppear:]
    4. -[DrawLineView drawRect:]
    5. -[DrawLineViewcontroller viewDidAppear:]
    从上述代码我们看到他是在视图将要显示之后和显示之前调用的。

.
.
.
通常我们需要进行一下的步骤进行绘制。

  • 1 获取当前的上下文(这里只能获取一次,并且只能在drawRect方法中获取)
  • 2 描述路径、形状(就是处理想要显示的样子)
  • 3 把描述好的路径、形状添加早上下文中
  • 4 显示上下文内容

.
.
.

1 画线

  • 第一步:先创建一个工程
  • 第二步:创建一个View的子类,因为要重写drawRect方法
  • 第三步:重写DrawRect
  • 第四步:先了解一下线段是如何绘制的,额……两个点确定一条直线,这些东西大家都懂,所以我们需要一个起点和一个终点来确定一条直线。

    3.png

代码如下:

  1. - (void)drawRect:(CGRect)rect {
  2. // Drawing code
  3. NSLog(@"%s",__func__);
  4. //1.获取上下文
  5. CGContextRef contextRef = UIGraphicsGetCurrentContext();
  6. //2.描述路径
  7. UIBezierPath * path = [UIBezierPath bezierPath];
  8. //起点
  9. [path moveToPoint:CGPointMake(10, 10)];
  10. //终点
  11. [path addLineToPoint:CGPointMake(100, 100)];
  12. //设置颜色
  13. [[UIColor whiteColor]setStroke];
  14. //3.添加路径
  15. CGContextAddPath(contextRef, path.CGPath);
  16. //显示路径
  17. CGContextStrokePath(contextRef);
  18. }

4.png


额外属性:CGContextSetLineWidth(contextRef, 5); //设置线宽

.
.
.

1 画矩形

  • 第一步:先创建一个工程
  • 第二步:创建一个View的子类,因为要重写drawRect方法
  • 第三步:重写DrawRect
  • 第四步:先了解一下矩形是如何绘制的,矩形是由四个边组成,所以我们画四条线段便可以画一个矩形。

    5.png

方法一:

  1. - (void)drawRect:(CGRect)rect {
  2. // Drawing code
  3. //1.获取上下文
  4. CGContextRef contextRef = UIGraphicsGetCurrentContext();
  5. //2.描述路径
  6. UIBezierPath * path = [UIBezierPath bezierPath];
  7. //起点
  8. [path moveToPoint:CGPointMake(10, 10)];
  9. //第二个点
  10. [path addLineToPoint:CGPointMake(100, 10)];
  11. //第三个点
  12. [path addLineToPoint:CGPointMake(100, 100)];
  13. //第四个点
  14. [path addLineToPoint:CGPointMake(10, 100)];
  15. //闭合路径 也等于 [path addLineToPoint:CGPointMake(10, 10)];
  16. [path closePath];
  17. //设置颜色
  18. [[UIColor greenColor]setStroke];
  19. //3.添加路径
  20. CGContextAddPath(contextRef, path.CGPath);
  21. //显示路径
  22. CGContextStrokePath(contextRef);
  23. }

效果图


方法一

方法二:通过一个起点和宽高,可计算出来矩形的大小位置

  1. - (void)drawRect:(CGRect)rect {
  2. // Drawing code
  3. //1.获取上下文
  4. CGContextRef contextRef = UIGraphicsGetCurrentContext();
  5. //2.描述路径
  6. UIBezierPath * path = [UIBezierPath bezierPathWithRect:CGRectMake(10, 10, 100, 100)];
  7. //设置颜色
  8. [[UIColor greenColor]set];
  9. //3.添加路径
  10. CGContextAddPath(contextRef, path.CGPath);
  11. //显示路径
  12. CGContextFillPath(contextRef);
  13. }

效果图:


方法二
画矩形总结:stroke:描边 、 fill:填充

//设置描边颜色
[[UIColor greenColor]setStroke];
//显示描边路径
CGContextStrokePath(contextRef);
//设置填充颜色
[[UIColor greenColor]set];
//显示填充路径
CGContextFillPath(contextRef);

.
.
.

3 画圆

  • 第一步:先创建一个工程
  • 第二步:创建一个View的子类,因为要重写drawRect方法
  • 第三步:重写DrawRect
  • 第四步:先了解一下圆形是如何绘制的,要确定圆心、半径,以及旋转的角度。

方法一:

  1. - (void)drawRect:(CGRect)rect {
  2. // Drawing code
  3. //1、获取当前上下文
  4. CGContextRef contextRef = UIGraphicsGetCurrentContext();
  5. //2.描述路径
  6. //ArcCenter:中心点
  7. //radius:半径
  8. //startAngle:起始角度
  9. //endAngle:结束角度
  10. //clockwise:是否逆时针
  11. UIBezierPath * path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.bounds.size.width*0.5, self.bounds.size.height*0.5) radius:self.bounds.size.width*0.4 startAngle:0 endAngle:M_PI*2 clockwise:NO];
  12. //3.添加路径到上下文
  13. CGContextAddPath(contextRef, path.CGPath);
  14. //4.设置颜色
  15. [[UIColor brownColor]setFill];
  16. //4.显示上下文 显示一个实心圆
  17. // CGContextFillPath(contextRef);
  18. //显示一个空心圆,描边
  19. CGContextStrokePath(contextRef);
  20. }

效果图:


效果图

方法二:通过话椭圆的方式去画圆,大家都知道圆就是椭圆的一个特殊存在。宽高一致的时候就是圆形。

  1. - (void)drawRect:(CGRect)rect {
  2. // Drawing code
  3. //1、获取当前上下文
  4. CGContextRef contextRef = UIGraphicsGetCurrentContext();
  5. //2.描述路径 这是画椭圆的方法,大家都知道
  6. UIBezierPath * path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(10, 10, 100, 100)];
  7. //3.添加路径到上下文
  8. CGContextAddPath(contextRef, path.CGPath);
  9. //4.设置颜色
  10. [[UIColor redColor]setFill];
  11. //4.显示上下文
  12. CGContextFillPath(contextRef);
  13. }

效果图

.
.
.

4 画文字

  • 第一步:先创建一个工程
  • 第二步:创建一个View的子类,因为要重写drawRect方法
  • 第三步:重写DrawRect
  • 第四步:写一段文字,把文字绘制到上下文中
  1. - (void)drawRect:(CGRect)rect {
  2. // Drawing code
  3. //1.获取当前上下文
  4. CGContextRef contextRef = UIGraphicsGetCurrentContext();
  5. //2.创建文字
  6. NSString * str = @"纸巾艺术";
  7. //会知道上下文
  8. [str drawInRect:rect withAttributes:nil];
  9. CGContextStrokePath(contextRef);
  10. }

基本版效果图

复杂版:

  1. - (void)drawRect:(CGRect)rect {
  2. // Drawing code
  3. //1.获取当前上下文
  4. CGContextRef contextRef = UIGraphicsGetCurrentContext();
  5. //2.创建文字
  6. NSString * str = @"纸巾艺术";
  7. //设置字体样式
  8. NSMutableDictionary * dict = [NSMutableDictionary dictionary];
  9. //NSFontAttributeName:字体大小
  10. dict[NSFontAttributeName] = [UIFont systemFontOfSize:25];
  11. //字体前景色
  12. dict[NSForegroundColorAttributeName] = [UIColor blueColor];
  13. //字体背景色
  14. dict[NSBackgroundColorAttributeName] = [UIColor redColor];
  15. //字体阴影
  16. NSShadow * shadow = [[NSShadow alloc]init];
  17. //阴影偏移量
  18. shadow.shadowOffset = CGSizeMake(2, 2);
  19. //阴影颜色
  20. shadow.shadowColor = [UIColor greenColor];
  21. //高斯模糊
  22. shadow.shadowBlurRadius = 5;
  23. dict[NSShadowAttributeName] = shadow;
  24. //字体间距
  25. dict[NSKernAttributeName] = @10;
  26. //绘制到上下文
  27. //从某一点开始绘制 默认 0 0点
  28. // [str drawAtPoint:CGPointMake(100, 100) withAttributes:nil];
  29. //绘制区域设置
  30. [str drawInRect:rect withAttributes:dict];
  31. //添加到上下文
  32. CGContextStrokePath(contextRef);
  33. }

复杂版效果图

.
.
.

5 画图片

  • 第一步:先创建一个工程
  • 第二步:创建一个View的子类,因为要重写drawRect方法
  • 第三步:重写DrawRect
  • 第四步:加载一张图片,绘制到上下文中
  1. - (void)drawRect:(CGRect)rect {
  2. // Drawing code
  3. //1.获取当前的上下文
  4. CGContextRef contextRef = UIGraphicsGetCurrentContext();
  5. //2.加载图片
  6. //这里顺便咯嗦一句:使用imageNamed加载图片是会有缓存的
  7. //我们这里只需要加载一次就够了,不需要多次加载,所以不应该保存这个缓存
  8. // UIImage * image = [UIImage imageNamed:@"222"]; //所以可以换一种方式去加载
  9. UIImage *image = [UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"222.png" ofType:nil]];
  10. // //绘制的大小位置
  11. // [image drawInRect:rect];
  12. // //从某个点开始绘制
  13. // [image drawAtPoint:CGPointMake(0, 0)];
  14. //绘制一个多大的图片,并且设置他的混合模式以及透明度
  15. //Rect:大小位置
  16. //blendModel:混合模式
  17. //alpha:透明度
  18. [image drawInRect:rect blendMode:kCGBlendModeNormal alpha:1];
  19. //从某一点开始绘制图片,并设置混合模式以及透明度
  20. //point:开始位置
  21. //blendModel:混合模式
  22. //alpha:透明度
  23. // [image drawAtPoint:CGPointMake(0, 0) blendMode:kCGBlendModeNormal alpha:1];
  24. //添加到上下文
  25. CGContextFillPath(contextRef);
  26. }

都写一起了!!!

.
.
.
.
.

6 综合实例:

1 重绘

实现一个下载进度条

  • 第一步:先创建一个工程
  • 第二步:创建一个View的子类,因为要重写drawRect方法
  • 第三步:重写DrawRect
  • 第四步:加载一张图片,绘制到上下文中
  1. - (void)drawRect:(CGRect)rect {
  2. CGFloat startA = - M_PI_2;
  3. CGFloat endA = - M_PI_2 + self.progress * M_PI * 2;
  4. NSLog(@"%f - %f - %f",self.progress,(3.14159265359*self.progress)/180,endA);
  5. UIBezierPath * path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.bounds.size.width*0.5, self.bounds.size.height*0.5) radius:self.bounds.size.width*0.5-10 startAngle:startA endAngle:endA clockwise:YES];
  6. [path stroke];
  7. }

这里我们可以看到我并没有获取当前的上下文,这里是因为[path stroke]; 已经帮我们完成了其余的操作。
其实内部实现还是一样的!!
基本版效果:


基本版效果


高能版:上面的只是完成了功能,但是却不好看!!然后我们稍稍的美化一下

  1. - (void)drawRect:(CGRect)rect {
  2. CGFloat startA = - M_PI_2;
  3. CGFloat endA = - M_PI_2 + self.progress * M_PI * 2;
  4. NSLog(@"%f - %f - %f",self.progress,(3.14159265359*self.progress)/180,endA);
  5. UIBezierPath * path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.bounds.size.width*0.5, self.bounds.size.height*0.5) radius:self.bounds.size.width*0.5-10 startAngle:startA endAngle:endA clockwise:YES];
  6. [[UIColor colorWithRed:self.progress green:(1-self.progress) blue:0 alpha:1]setStroke];
  7. path.lineWidth = 5;
  8. [path stroke];
  9. }

动画版


.
.
.
.
.

2 不同颜色的线

先跑出问题!


线


这种线怎么处理!我们先实现三条线

  1. - (void)drawRect:(CGRect)rect {
  2. // Drawing code
  3. UIBezierPath * path = [UIBezierPath bezierPath];
  4. //设置线宽
  5. path.lineWidth = 5;
  6. //第一条线
  7. [[UIColor purpleColor]setStroke];
  8. [path moveToPoint:CGPointMake(10, 10)];
  9. [path addLineToPoint:CGPointMake(10, 100)];
  10. //第二条线
  11. [[UIColor orangeColor]setStroke];
  12. [path moveToPoint:CGPointMake(30, 10)];
  13. [path addLineToPoint:CGPointMake(30, 100)];
  14. //第三条线
  15. [[UIColor greenColor]setStroke];
  16. [path moveToPoint:CGPointMake(50, 10)];
  17. [path addLineToPoint:CGPointMake(50, 100)];
  18. //使用描边方式添加到上下文中
  19. [path stroke];
  20. }

你可能想当然的就这么做了,可是你发现效果是这样子的!!!


哎呀我去,为什么


其实是这样子的


先设置了紫色

设置了橙色

设置了绿色

所以,最后显示的就是绿色!!!!

这里我们还要了解一个东西!
上下文的状态栈。


21.png

方法一:

  1. - (void)drawRect:(CGRect)rect {
  2. // Drawing code
  3. //1 获取上下文
  4. //分别设置线段的颜色
  5. CGContextRef purple = UIGraphicsGetCurrentContext();
  6. [[UIColor purpleColor]setStroke];
  7. CGContextSaveGState(purple);
  8. CGContextRef orange = UIGraphicsGetCurrentContext();
  9. [[UIColor orangeColor]setStroke];
  10. CGContextSaveGState(orange);
  11. CGContextRef green = UIGraphicsGetCurrentContext();
  12. [[UIColor greenColor]setStroke];
  13. CGContextSaveGState(green);
  14. UIBezierPath * path = [UIBezierPath bezierPath];
  15. //设置线宽
  16. path.lineWidth = 5;
  17. //把紫色的上下文从栈中取出来
  18. CGContextRestoreGState(purple);
  19. //第一条线
  20. [[UIColor purpleColor]setStroke];
  21. [path moveToPoint:CGPointMake(10, 10)];
  22. [path addLineToPoint:CGPointMake(10, 100)];
  23. [path stroke];
  24. //把紫色的上下文从栈中取出来
  25. CGContextRestoreGState(orange);
  26. path = [UIBezierPath bezierPath];
  27. //设置线宽
  28. path.lineWidth = 9;
  29. //第二条线
  30. [[UIColor orangeColor]setStroke];
  31. [path moveToPoint:CGPointMake(30, 10)];
  32. [path addLineToPoint:CGPointMake(30, 100)];
  33. [path stroke];
  34. //把紫色的上下文从栈中取出来
  35. CGContextRestoreGState(green);
  36. path = [UIBezierPath bezierPath];
  37. //设置线宽
  38. path.lineWidth = 3;
  39. //第三条线
  40. [[UIColor greenColor]setStroke];
  41. [path moveToPoint:CGPointMake(50, 10)];
  42. [path addLineToPoint:CGPointMake(50, 100)];
  43. [path stroke];
  44. }

方法二:

  1. - (void)drawRect:(CGRect)rect {
  2. // Drawing code
  3. [[self bezierPathWithPoint:CGPointMake(10, 10) endPoint:CGPointMake(10, 180) lineColor:[UIColor purpleColor] lineWidth:6] stroke];
  4. [[self bezierPathWithPoint:CGPointMake(50, 10) endPoint:CGPointMake(50, 180) lineColor:[UIColor greenColor] lineWidth:6] stroke];
  5. [[self bezierPathWithPoint:CGPointMake(90, 10) endPoint:CGPointMake(90, 180) lineColor:[UIColor orangeColor] lineWidth:6] stroke];
  6. }
  7. - (UIBezierPath *)bezierPathWithPoint:(CGPoint)startPoint endPoint:(CGPoint) endPoint lineColor:(UIColor*)lineColor lineWidth:(CGFloat)lineWidth{
  8. UIBezierPath * path = [UIBezierPath bezierPath];
  9. [lineColor setStroke];
  10. path.lineWidth = lineWidth;
  11. [path moveToPoint:startPoint];
  12. [path addLineToPoint:endPoint];
  13. return path;
  14. }

了解了原理之后就这样子写快点啦

demo地址

声明:本文内容由网友自发贡献,转载请注明出处:【wpsshop】
推荐阅读
相关标签
  

闽ICP备14008679号