和上一篇手势解锁不一样,手势解锁只画了一条路径,从触摸开始--》触摸移动--》触摸结束 ,然后路径完成了,渲染出来就是手势解锁了;
这次涂鸦想做到的效果是可以画很多次线段或弧,每次又可以设置不同的宽度和颜色,然后还要有撤销、清屏、橡皮擦的功能,那就需要画很多条路径了,然后每条路径有自己的颜色和宽度,那么
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