响应者对象:继承了UIResponder的对象
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
移动:每移动一点就会调用一次;
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
触摸结束:
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
触摸事件被打断:
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
远程控制事件:
- (void)remoteControlReceivedWithEvent:(UIEvent *)event NS_AVAILABLE_IOS(4_0);
UIToch对象:
触摸时,会为每个手指创建一个相关联的UITouch对象,保存着跟手指相关的信息,触摸的位置、时间等;
手指移动时,系统会更新同一个UITouch对象,一直保存手指触摸的位置;
手指移开时,销毁UITouch;
获取touch对象:UITouch * touch = [touches anyObject];
触摸点所在的view
touch.view
触摸点所在的window
touch.window
获取当前触摸点的位置,相对于哪个view的位置,填nil为相对于window;
CGPoint point = [touch locationInView:touch.view];
获取上一个触摸点的位置,可以用于touchesMoved方法中
CGPoint point2 = [touch previousLocationInView:touch.view];
效果图:
原理:利用view的触摸事件,使用UIBezierPath对象进行涂鸦,UIBezierPath可以储存线段上的所有点,当成一条路径使用,并且被渲染到视图上;根据触摸点位置变化设置跟踪笔头;
我仅仅实现了效果,封装的不是很好完善,推荐这位大神的博客,封装思想很好点击这里
我有一个继承自UIView的tuyaView来作为白色涂鸦板,一个设置画笔属性的UIViewController,一个用于储存画笔属性的数据manager类;
图片
步骤:
涂鸦板view:
1、自定义一个继承自UIView的view作为涂鸦板,UIView继承自UIResponder,可以接收触摸事件; 声明三个数组属性用于存放线段以及线段属性,并且在懒加载中初始化;
2、在view的touchBegin事件中,新建一个UIBezierPath对象,使用它的moveToPoint方法将当前的触摸点设为这条线段的起点,并且将他存放到我们的线段数组中,从数据管理器中拿出线段的各种属性存放在属性数组中。初始化圆形画笔笔头,添加到涂鸦板上,中心位为触摸点;
4、监控手指的移动,将剩余线段点加入到上面创建的UIBezierPath对象中;从数组中取出贝塞尔对象,使用它的addLineToPoint方法,将移动后得到的当前点储存上;并且调用view的setNeedDisplay方法,重绘view;设置画笔笔头跟踪手指触摸移动。当触摸结束时,将笔头view移除;
5、实现view的drawRect方法:此方法用于绘制view,第四步设置了每当touchmove时都会调用此方法,从数组中拿出每一个贝塞尔对象,将它画到view上,并且取出相应的画笔样式;如果用户选取了照片就将照片绘制上去,这样绘制功能就实现了;
6、实现添加图片、退一步、清空画布、保存图片四个方法;
tuyaView.m
1 @interface tuyaView ()
2 保存每条线段
3 @property (nonatomic, strong) NSMutableArray * linePaths;
4 保存每条线段的画笔大小
5 @property (nonatomic, strong) NSMutableArray * penValues;
6 保存每条线段颜色
7 @property (nonatomic, strong) NSMutableArray * penColors;
8 数据管理器
9 @property (nonatomic, strong) manager * m;
10 画笔 笔头;
11 @property (nonatomic, strong) UIView * touchPointView;
12
13 @end
14
15 @implementation tuyaView
16 懒加载中初始化各个数组
17 -(manager *)m
18 {
19 if (!_m)
20 {
21 _m = [manager shared];
22 }
23 return _m;
24 }
25
26 -(NSMutableArray *)penValues
27 {
28 if (!_penValues)
29 {
30 _penValues = [NSMutableArray array];
31 }
32 return _penValues;
33 }
34
35 - (NSMutableArray *)linePaths
36 {
37 if (!_linePaths) {
38 _linePaths = [NSMutableArray array];
39 }
40 return _linePaths;
41 }
42
43 -(NSMutableArray *)penColors
44 {
45 if (!_penColors) {
46 _penColors = [NSMutableArray array];
47 }
48 return _penColors;
49 }
50
51
52 触摸事件开始
53 -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
54 {
55 UITouch * touch = [touches anyObject];
56 CGPoint point = [touch locationInView:touch.view];
57 //
58 UIBezierPath * linePath = [UIBezierPath bezierPath];
59 [linePath moveToPoint:point];
60 [self.linePaths addObject:linePath];
61
62 //保存线条粗细
63 float penValue = self.m.penValue;
64 [self.penValues addObject:[NSNumber numberWithFloat:penValue ]];
65 //保存线条颜色
66 UIColor * penColor = self.m.penColor;
67 [self.penColors addObject:penColor];
68
69 //创建触控点
70 CGFloat touchRadius = self.m.penValue + 10;
71 self.touchPointView = [[UIView alloc] initWithFrame:CGRectMake(point.x - touchRadius * 0.5, point.y - touchRadius * 0.5, touchRadius, touchRadius)];
72 self.touchPointView.layer.cornerRadius = touchRadius * 0.5;
73 self.touchPointView.clipsToBounds = YES;
74 self.touchPointView.backgroundColor = [UIColor redColor];
75 self.touchPointView.alpha = 0.5;
76 [self addSubview:self.touchPointView];
77 }
78
79 手指移动
80 -(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
81 {
82 UITouch * touch = [touches anyObject];
83 CGPoint touchPoint = [touch locationInView:touch.view];
84
85 UIBezierPath * linePath = [self.linePaths lastObject];
86 [linePath addLineToPoint:touchPoint];
87
88 //触控点移动
89 CGPoint current = [touch locationInView:touch.view];
90 CGPoint pre = [touch previousLocationInView:touch.view];
91 CGPoint center = self.touchPointView.center;
92 center.x += current.x - pre.x;
93 center.y += current.y - pre.y;
94 self.touchPointView.center = center;
95
96 [self setNeedsDisplay];
97 }
98
99 触摸结束
100 -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
101 {
102 [self.touchPointView removeFromSuperview];
103 }
104
105
106 绘制view
107 -(void)drawRect:(CGRect)rect
108 {
109 [self.tuyaImage drawInRect:CGRectMake(0, 0, rect.size.width, rect.size.height)];
110
111 for (int i = 0; i < self.linePaths.count; i ++)
112 {
113 UIBezierPath * path = self.linePaths[i];
114 //取出线条宽度
115 float penValue = [self.penValues[i] floatValue];
116 [path setLineWidth:penValue];
117 //取出线条颜色
118 UIColor * color = self.penColors[i];
119 [color setStroke];
120
121 [path setLineJoinStyle:kCGLineJoinRound];
122 [path setLineCapStyle:kCGLineCapRound];
123 [path stroke];
124 }
125 }
126
127 选取图片
128 - (void)fetchPictureWith:(UIImage *)image
129 {
130 self.tuyaImage = image;
131 [self setNeedsDisplay];
132 }
133
134 退后一步
135 - (void)backTheLastTime
136 {
137 [self.linePaths removeLastObject];
138 [self.penValues removeLastObject];
139 [self.penColors removeLastObject];
140 [self setNeedsDisplay];
141 }
142
143 清空画布
144 - (void)cleanAllPainted
145 {
146 [self.linePaths removeAllObjects];
147 [self.penValues removeAllObjects];
148 [self.penColors removeAllObjects];
149 self.tuyaImage = nil;
150 [self setNeedsDisplay];
151 }
152
153 保存图片到手机相册
154 - (void)savePicture
155 {
156 //1、开启上下文
157 UIGraphicsBeginImageContextWithOptions(self.frame.size, YES, 0.0);
158 //2、将控制器view的layer渲染到上下文,想要截啥就把哪个图层拿出来渲染
159 [self.layer renderInContext:UIGraphicsGetCurrentContext()];
160 //3、取出图片
161 UIImage * newImage = UIGraphicsGetImageFromCurrentImageContext();
162 //保存到手机相册
163 UIImageWriteToSavedPhotosAlbum(newImage, nil, nil, nil);
164 //关闭上下文
165 UIGraphicsEndImageContext();
166 }
属性控制器:1、从数据管理器中取出数据显示到自身view上。2、当画笔样式被修改时,将数据保存到管理器中。3、和tuyaView通过UINavigationController跳转,各种控件通过Storyboard实现;
PropertyView.m
1 @interface PropertyView ()
2
3 @property (weak, nonatomic) IBOutlet UILabel *lalPen;
4 @property (weak, nonatomic) IBOutlet UISlider *slider;
5
6 @property (nonatomic, strong)manager * m;
7 @property (weak, nonatomic) IBOutlet UISlider *sliderRed;
8 @property (weak, nonatomic) IBOutlet UISlider *sliderGreen;
9 @property (weak, nonatomic) IBOutlet UISlider *sliderBlue;
10 @property (weak, nonatomic) IBOutlet UISlider *sliderAlpha;
11
12 @property (weak, nonatomic) IBOutlet UILabel *lalRed;
13 @property (weak, nonatomic) IBOutlet UILabel *lalGreen;
14 @property (weak, nonatomic) IBOutlet UILabel *lalBlue;
15 @property (weak, nonatomic) IBOutlet UILabel *lalAlpha;
16
17 @property (weak, nonatomic) IBOutlet UIView *colorView;
18
19 @end
20
21 @implementation PropertyView
22
23 -(void)viewDidLoad
24 {
25 [super viewDidLoad];
26 self.m = [manager shared];
27 self.slider.value = self.m.penValue;
28 self.lalPen.text = [NSString stringWithFormat:@"画笔宽度:%0.1lf",self.m.penValue];
29
30 self.lalRed.text = self.lalRed.text = [NSString stringWithFormat:@"红:%0.0f",self.m.red];
31 self.lalGreen.text = [NSString stringWithFormat:@"红:%0.0f",self.m.green];
32 self.lalBlue.text = [NSString stringWithFormat:@"红:%0.0f",self.m.blue];
33 self.lalAlpha.text = [NSString stringWithFormat:@"透明度:%0.0f",1 - self.m.penAlpha];
34
35 self.sliderRed.value = self.m.red;
36 self.sliderGreen.value = self.m.green;
37 self.sliderBlue.value = self.m.blue;
38 self.sliderAlpha.value = 1 - self.m.penAlpha;
39
40 self.colorView.backgroundColor = self.m.penColor;
41 }
42
43 - (IBAction)PenSliderValueChanged:(UISlider *)sender
44 {
45 self.lalPen.text = [NSString stringWithFormat:@"画笔宽度:%0.1lf",sender.value];
46 self.m.penValue = sender.value;
47 }
48
49 当4slider改变时回调同一个方法;
50 - (IBAction)ColorChanged:(UISlider *)sender {
51 switch (sender.tag) {
52 case 1:
53 self.lalRed.text = [NSString stringWithFormat:@"红:%0.0f",sender.value];
54 self.m.red = sender.value;
55 break;
56 case 2:
57 self.lalGreen.text = [NSString stringWithFormat:@"绿:%0.0f",sender.value];
58 self.m.green = sender.value;
59 break;
60 case 3:
61 self.lalBlue.text = [NSString stringWithFormat:@"蓝:%0.0f",sender.value];
62 self.m.blue = sender.value;
63 break;
64 case 4:
65 self.lalAlpha.text = [NSString stringWithFormat:@"透明度:%0.1f",sender.value];
66 self.m.penAlpha = 1 - sender.value;
67 break;
68
69 default:
70 break;
71 }
72 self.colorView.backgroundColor = self.m.penColor;
73 }
74
75 @end
数据管理器:储存画笔样式
manager.h
1 @interface manager : NSObject
2
3 @property (nonatomic, assign) CGFloat penValue;
4
5 @property (nonatomic, assign) CGFloat red;
6 @property (nonatomic, assign) CGFloat green;
7 @property (nonatomic, assign) CGFloat blue;
8 @property (nonatomic, strong) UIColor * penColor;
9 @property (nonatomic, assign) CGFloat penAlpha;
10
11 + (instancetype)shared;
12
13 @end
manager.m
1 + (instancetype)shared
2 {
3 static manager * m = nil;
4 static dispatch_once_t onceToken;
5 dispatch_once(&onceToken, ^{
6 m = [[manager alloc] init];
7 });
8 return m;
9 }
10 初始化颜色
11 -(UIColor *)penColor
12 {
13 _penColor = [UIColor colorWithRed:self.red / 255 green:self.green/ 255 blue:self.blue / 255 alpha:1 - self.penAlpha];
14 return _penColor;
15 }
16
17 初始化画笔宽度
18 -(CGFloat)penValue
19 {
20 if (!_penValue) {
21 _penValue = 1.0;
22 }
23 return _penValue;
24 }