专栏首页谈补锅Quartz2D复习(三) --- 涂鸦

Quartz2D复习(三) --- 涂鸦

和上一篇手势解锁不一样,手势解锁只画了一条路径,从触摸开始--》触摸移动--》触摸结束 ,然后路径完成了,渲染出来就是手势解锁了;

这次涂鸦想做到的效果是可以画很多次线段或弧,每次又可以设置不同的宽度和颜色,然后还要有撤销、清屏、橡皮擦的功能,那就需要画很多条路径了,然后每条路径有自己的颜色和宽度,那么

UIBezierPath类也实现不了,需要自定义一个类,继承自UIBezierPath,然后再增加自己的颜色和宽度属性。

效果截图:

  涂鸦了 

  橡皮擦擦除 

保存到相册

代码:

1、自定义PaintingBezierPath类继承自UIBezierPath类,增加一个自定义路径颜色的属性;自定义构造函数,设置颜色和路径宽度

PaintingBezierPath.h文件代码:

#import <UIKit/UIKit.h>

@interface PaintingBezierPath : UIBezierPath

@property (nonatomic, retain) UIColor *color; //线段的颜色

- (instancetype)initWithColor: (UIColor *)color WithWidth: (CGFloat)width WithStartPoint: (CGPoint)startPoint;

@end

PaintingBezierPath.m文件代码:

 1 //
 2 //  PaintingBezierPath.m
 3 //  tan_iosTwo
 4 //
 5 //  Created by xiaom on 15/7/22.
 6 //
 7 //  为了自定义每个轨迹的宽度和颜色,需要增加一个自定义方法
 8 
 9 #import "PaintingBezierPath.h"
10 
11 @implementation PaintingBezierPath
12 
13 - (instancetype)initWithColor:(UIColor *)color WithWidth:(CGFloat)width WithStartPoint:(CGPoint)startPoint{
14     if (self = [super init]){
15         self.color = color;
16         self.lineWidth = width;
17         self.lineJoinStyle = kCGLineJoinRound;
18         self.lineCapStyle = kCGLineCapRound;
19         [self moveToPoint:startPoint];
20     }
21     return self;
22 }
23 
24 @end

2、自定义view, 用来展示涂鸦,名称为:PaintingView

PaintingView.h文件代码:

#import <UIKit/UIKit.h>

@interface PaintingView : UIView

@property (nonatomic, assign) CGFloat lineWidth; //涂鸦的线段宽度
@property (nonatomic, strong) UIColor *lineColor; //涂鸦的线段颜色

- (void)cancelPainting; //撤销涂鸦
- (void)clearScreen; //清屏
- (void)saveImgToAlbum; //保存相片到到手机相册里

@end

PaintingView.m文件代码:

  1 //  绘画, 涂鸦
  2 
  3 #import "PaintingView.h"
  4 #import "PaintingBezierPath.h"
  5 
  6 @interface PaintingView()
  7 
  8 @property (nonatomic, retain) NSMutableArray *paths; //涂鸦路径数组
  9 @property (nonatomic, retain) PaintingBezierPath *currentPath; //当前正在绘制的path
 10 
 11 @end
 12 
 13 @implementation PaintingView
 14 
 15 //代码创建对象会调用: 使用
 16 - (instancetype)initWithFrame:(CGRect)frame{
 17     if (self = [super initWithFrame:frame]){
 18         //NSLog(@"frame...%s", __func__);
 19     }
 20     return self;
 21 }
 22 
 23 //xib创建会调用
 24 - (instancetype)initWithCoder:(NSCoder *)aDecoder{
 25     if (self = [super initWithCoder:aDecoder]){
 26         //NSLog(@"coder.. %s", __func__);
 27     }
 28     return self;
 29 }
 30 
 31 //监听触摸开始 ,方法继承自UIResponder
 32 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
 33     PaintingBezierPath *path = [[PaintingBezierPath alloc] initWithColor:self.lineColor WithWidth:self.lineWidth WithStartPoint:[self currentPoint:touches]];
 34     
 35     [self.paths addObject:path]; //将路径记录到数组中
 36     self.currentPath = path;
 37     
 38     [self setNeedsDisplay];  //调用方法,重新绘制
 39 }
 40 
 41 //监听触摸移动中
 42 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event{
 43     //追踪每次路径的移动过程
 44     [self.currentPath addLineToPoint:[self currentPoint:touches]];
 45     
 46     [self setNeedsDisplay]; //调用方法,重新绘制
 47 }
 48 
 49 //获取view对象中的当前位置
 50 - (CGPoint)currentPoint: (NSSet *)touches{
 51     UITouch *touch = [touches anyObject];
 52     return [touch locationInView:self];
 53 }
 54 
 55 //次方法是UIView的分类@interface UIView(UIViewRendering)中添加的方法
 56 //setNeedsDisplay方法也是此分类中的方法
 57 - (void)drawRect:(CGRect)rect{
 58     for (int i = 0; i < self.paths.count; i++) {
 59         PaintingBezierPath *path = [self.paths objectAtIndex:i];
 60         [path.color set];
 61         [path stroke];  //渲染
 62     }
 63 }
 64 
 65 #pragma mark - 自定义方法实现
 66 //撤销
 67 - (void)cancelPainting{
 68     [self.paths removeLastObject]; //移除最后一个路径对象
 69     [self setNeedsDisplay]; //重新绘制
 70 }
 71 
 72 //清屏
 73 - (void)clearScreen{
 74     [self.paths removeAllObjects]; //移除所有路径
 75     self.lineColor = nil; //颜色赋空
 76     [self setNeedsDisplay]; //重新绘制
 77 }
 78 
 79 //保存图片到相册
 80 - (void)saveImgToAlbum{
 81     //1、开启图形上下文
 82     UIGraphicsBeginImageContextWithOptions(self.bounds.size, NO, 0.0);
 83     //2、获取当前上下文
 84     CGContextRef ctr = UIGraphicsGetCurrentContext();
 85     //3、渲染当前View的图层到上下文中
 86     [self.layer renderInContext:ctr];
 87     //4、获取新图片
 88     UIImage *newImg = UIGraphicsGetImageFromCurrentImageContext();
 89     //5、关闭图形上下文
 90     UIGraphicsEndImageContext();
 91     //6、保存图片到相册中
 92     UIImageWriteToSavedPhotosAlbum(newImg, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
 93 }
 94 
 95 //保存图片到相册完成之后的处理
 96 - (void)image:(UIImage *)image didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{
 97     UILabel *lbl = [[UILabel alloc] initWithFrame:CGRectMake(60, 150, 200, 100)];
 98     [lbl setBackgroundColor:[UIColor blackColor]];
 99     lbl.textAlignment = NSTextAlignmentCenter;
100     lbl.textColor = [UIColor yellowColor];
101     
102     if (error){ //保存失败
103         lbl.text = @"保存失败";
104     }
105     else{ //保存成功
106         lbl.text = @"保存成功";
107     }
108     [self addSubview:lbl];
109     
110     [UIView animateWithDuration:2.0 animations:^{
111         lbl.alpha = 0.1;
112     } completion:^(BOOL finished) {
113         [lbl removeFromSuperview];
114     }];
115 }
116 
117 //设置对象默认属性值
118 - (CGFloat)lineWidth{
119     if (_lineWidth < 1){
120         _lineWidth = 1;
121     }
122     return _lineWidth;
123 }
124 
125 - (UIColor *)lineColor{
126     if (_lineColor == nil){
127         _lineColor = [UIColor blackColor];
128     }
129     return _lineColor;
130 }
131 
132 - (NSMutableArray *)paths{
133     if (_paths == nil){
134         _paths = [[NSMutableArray alloc] init];
135     }
136     return _paths;
137 }
138 
139 /*
140 // Only override drawRect: if you perform custom drawing.
141 // An empty implementation adversely affects performance during animation.
142 - (void)drawRect:(CGRect)rect {
143     // Drawing code
144 }
145 */
146 
147 @end

3、自定义控制器展示PaintingView

DoodleViewController.h文件:

#import <UIKit/UIKit.h>

@interface DoodleViewController : UIViewController

@end

DoodleViewController.m

  1 //  信手涂鸦
  2 
  3 #import "DoodleViewController.h"
  4 #import "PaintingView.h"
  5 
  6 @interface DoodleViewController ()
  7 
  8 @property (nonatomic, retain) PaintingView *paintV; //涂鸦的画板
  9 
 10 @end
 11 
 12 @implementation DoodleViewController
 13 
 14 - (void)viewDidLoad {
 15     [super viewDidLoad];
 16     // Do any additional setup after loading the view.
 17     [self.view setBackgroundColor:[UIColor whiteColor]];
 18     
 19     //自定义View涂鸦
 20     PaintingView *v = [[PaintingView alloc] initWithFrame:CGRectMake(0, 80, 320, 450)];
 21     [v setBackgroundColor:[UIColor grayColor]];
 22     [v setAlpha:0.6];
 23     [self.view addSubview:v];
 24     self.paintV = v;
 25     
 26     [self addReturnBtn];    //添加返回按钮
 27     [self addDoodleSetWidthAndColor]; //增加设置涂鸦的宽度和颜色设置
 28 }
 29 
 30 //添加返回按钮
 31 - (void)addReturnBtn{
 32     UIButton *returnBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 20, 50, 30)];
 33     [returnBtn setTitle:@"返回" forState:UIControlStateNormal];
 34     [returnBtn addTarget:self action:@selector(returnPrePage) forControlEvents:UIControlEventTouchUpInside];
 35     [returnBtn setTitleColor:[UIColor redColor] forState:UIControlStateNormal];
 36     [self.view addSubview:returnBtn];
 37 }
 38 
 39 //添加涂鸦宽度设置和颜色设置
 40 - (void)addDoodleSetWidthAndColor{
 41     //1、增加UISlider用来设置可调节宽度
 42     UISlider *slider = [[UISlider alloc] initWithFrame:CGRectMake(50, 20, 80, 30)];
 43     slider.maximumValue = 15.0f; //最大值
 44     slider.value = 3.0f;    //默认为1
 45     self.paintV.lineWidth = slider.value;
 46     [slider addTarget:self action:@selector(setLineWidth:) forControlEvents:UIControlEventValueChanged]; //绑定值改变事件
 47     [self.view addSubview:slider];
 48     
 49     //2、添加颜色选择按钮
 50     NSArray *colors = @[[UIColor redColor], [UIColor yellowColor], [UIColor greenColor], [UIColor blueColor], [UIColor purpleColor], [UIColor brownColor]];
 51     for (int i = 0; i < colors.count; i++) {
 52         CGFloat x =  140 + 30 * i;
 53         UIButton *colorBtn = [[UIButton alloc] initWithFrame:CGRectMake(x, 25, 20, 20)];
 54         [colorBtn setBackgroundColor:[colors objectAtIndex:i]];
 55         [colorBtn addTarget:self action:@selector(setLineColor:) forControlEvents:UIControlEventTouchUpInside];
 56         [self.view addSubview:colorBtn];
 57     }
 58     
 59    
 60     //第二行
 61     //3、添加撤销按钮
 62     UIButton *cancelBtn = [[UIButton alloc] initWithFrame:CGRectMake(0, 55, 60, 25)];
 63     [cancelBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
 64     [cancelBtn setTitle:@"撤销" forState:UIControlStateNormal];
 65     [cancelBtn addTarget:self action:@selector(cancelPainting) forControlEvents:UIControlEventTouchUpInside];
 66     [self.view addSubview:cancelBtn];
 67     
 68     //4、清屏按钮
 69     UIButton *clearScreenBtn = [[UIButton alloc] initWithFrame:CGRectMake(70, 55, 60, 25)];
 70     [clearScreenBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
 71     [clearScreenBtn setTitle:@"清屏" forState:UIControlStateNormal];
 72     [clearScreenBtn addTarget:self action:@selector(clearScreen) forControlEvents:UIControlEventTouchUpInside];
 73     [self.view addSubview:clearScreenBtn];
 74     
 75     //5、添加一个橡皮擦
 76     UIButton *brushBtn = [[UIButton alloc] initWithFrame:CGRectMake(140, 55, 60, 25)];
 77     [brushBtn setTitle:@"橡皮擦" forState:UIControlStateNormal];
 78     [brushBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
 79     [brushBtn addTarget:self action:@selector(brush) forControlEvents:UIControlEventTouchUpInside];
 80     [self.view addSubview:brushBtn];
 81     
 82     //6、保存到相册按钮
 83     UIButton *saveBtn = [[UIButton alloc] initWithFrame:CGRectMake(210, 55, 100, 25)];
 84     [saveBtn setTitle:@"保存到相册" forState:UIControlStateNormal];
 85     [saveBtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
 86     [saveBtn addTarget:self action:@selector(saveImgToAlbum) forControlEvents:UIControlEventTouchUpInside];
 87     [self.view addSubview:saveBtn];
 88 }
 89 
 90 //调节宽度
 91 - (void)setLineWidth:(UISlider *)sender{
 92     [self.paintV setLineWidth:sender.value];
 93 }
 94 
 95 //调节颜色
 96 - (void)setLineColor: (UIButton *)sender{
 97     [self.paintV setLineColor:sender.backgroundColor];
 98 }
 99 
100 //设置橡皮擦
101 - (void)brush{
102     self.paintV.lineColor = self.paintV.backgroundColor;
103     if (self.paintV.lineWidth < 5) self.paintV.lineWidth = 5;
104 }
105 //撤销
106 - (void)cancelPainting{
107     [self.paintV cancelPainting];
108 }
109 //清屏
110 - (void)clearScreen{
111     [self.paintV clearScreen];
112 }
113 
114 //保存图片到相册
115 - (void)saveImgToAlbum{
116     [self.paintV saveImgToAlbum];
117 }
118 
119 //返回上一页
120 - (void)returnPrePage{
121     [self dismissViewControllerAnimated:YES completion:nil];
122 }
123 
124 - (void)didReceiveMemoryWarning {
125     [super didReceiveMemoryWarning];
126     // Dispose of any resources that can be recreated.
127 }
128 
129 /*
130 #pragma mark - Navigation
131 
132 // In a storyboard-based application, you will often want to do a little preparation before navigation
133 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
134     // Get the new view controller using [segue destinationViewController].
135     // Pass the selected object to the new view controller.
136 }
137 */
138 
139 @end

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 自定义UITableViewCell实现左滑动多菜单功能LeftSwipe

    1、使用自定义UITableViewCell + UISwipeGestureRecognizer + 代理 实现;

    tandaxia
  • Quartz2D复习(二) --- 手势解锁

    这次支付宝手机客户端升级,把手势解锁那个功能去掉了,引起很多人的抱怨,觉得少了手势解锁的保护,个人信息容易泄漏了。。。

    tandaxia
  • 机试题:地图定位、拍照并显示、录制视频并播放

      这两天参加面试,有个公司先出了机试题,然后才能进入下一步,机试题大意是要求实现:地图定位、拍照并显示照片、录制视频并且播放视频三个小功能。

    tandaxia
  • 使用Python写Windows Ser

    如果你想用Python开发Windows程序,并让其开机启动等,就必须写成windows的服务程序Windows Service,用Python来做这个事情必...

    py3study
  • 利用Python编写一个行业专用的小计算器

    前言:本文讲述的是如何利用python编程制作一个适用于指定行业的计算器,方便计算结果,涵盖的知识点由Python编写GUI界面程序,利用爬虫采集实时的汇率数据...

    用户7886150
  • 用Python做一个翻译软件

    前两天吃了平哥的一波狗粮,他给女朋友写了一个翻译软件,自己真真切切的感受到了程序员的浪漫。在学习requests请求的时候做过类似的Demo,给百度翻译发送一个...

    小小詹同学
  • 商业篇 | 使用python开发性格分析工具卖钱

    如此不均衡的贫富差距,各行业的领导者如何能管理好公司,让员工们即努力产出,又能安于现状呢?每个领导者必学的一门课程就是职场心理学。只有你充分了解员工心理与对应的...

    叫我龙总
  • PyQt5 动画类--跳舞的火柴人

    PyQt5.QtCore中的 QPropertyAnimation可以实现动画功能。

    用户6021899
  • PyQt5信号、定时器及多线程

    信号是用于界面自动变化的一个工具,原理是信号绑定了一个函数,当信号被触发时函数即被调用

    嘘、小点声
  • python的tkinter编程(九)Text多行文本框的详细解读

    一天不写程序难受

扫码关注云+社区

领取腾讯云代金券