监听屏幕触摸事件实现涂鸦

一、直接上图

iOS-Simulator-Screen-Shot-2014年12月19日-下午5.09.07iOS-Simulator-Screen-Shot-2014年12月19日-下午5.13.07iOS-Simulator-Screen-Shot-2014年12月19日-下午5.15.02

二、设计说明

1、UIView继承自UIResponder,UIResponder能响应所有的事件与用户进行交互,如:触摸事件(单点/多点触控)、加速事件(重力感应)、远程事件(耳机播放/暂停/下一曲)

2、触摸事件主要涉及以下4个方法

// 开始触屏时调用,只调用一次
– (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;

3、结合上述相关方法,使用Quartz2D绘制图形到当前视图

4、将图形保存到本地相册

三、关键代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#import "SAView.h"
 
@implementation SAView
 
#pragma mark - 初始化
- (NSMutableArray *)paths
{
    if (_paths == nil) {
        _paths = [NSMutableArray array];
    }
    return _paths;
}
// 图层渲染方法,每调用setNeedsDisplay方法都会调用此方法
- (void)drawRect:(CGRect)rect
{
    for (UIBezierPath *path in self.paths) {
        [path stroke];
    }
}
 
#pragma mark - 触摸事件处理
// 开始涂鸦(以每一笔为基本单位),接触屏幕时调用一次
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touchesBegan");
    // 创建一个贝赛尔曲线对象,设置相关属性(圆角线条、线条粗细)
    UIBezierPath *path = [UIBezierPath bezierPath];
    path.lineCapStyle = kCGLineCapRound;
    path.lineJoinStyle = kCGLineJoinRound;
    path.lineWidth = 5;
 
    // 通过touch事件获取位置变化传入给贝赛尔曲线
    CGPoint point = [[touches anyObject] locationInView:self];
    [path moveToPoint:point];
 
    // 将该曲线对象加入到数组
    [self.paths addObject:path];
 
    // 刷新图层
    [self setNeedsDisplay];
}
 
// 移动手指,手指移动时会反复调用,频率较高
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touchesMoved");
    /* 获取当前画笔跟随触摸移动继续绘制
     * 该方法调用频率非常高,一点点移动都会调用多次
     * 所以画出的多条折线视觉上是连续的
     */
    UIBezierPath *path = [self.paths lastObject];
    CGPoint point = [[touches anyObject] locationInView:self];
    [path addLineToPoint:point];
 
    // 刷新图层
    [self setNeedsDisplay];
 
}
 
// 结束触摸,即手指离开时调用一次
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"touchesEnded");
    [self touchesMoved:touches withEvent:event];
}
 
#pragma mark - 按钮事件处理
// 回退,即移除上一个画笔对象
- (IBAction)back:(id)sender
{
    [self.paths removeLastObject];
    [self setNeedsDisplay];
}
// 清除,移除所有画笔对象
- (IBAction)clean:(id)sender
{
    [self.paths removeAllObjects];
    [self setNeedsDisplay];
}
// 保存图片到本地相册
- (IBAction)save:(id)sender
{
    // 开启图片上下文
    UIGraphicsBeginImageContext(self.frame.size);
 
    // 将当前view上内存渲染到当前上下文
    [self.layer renderInContext:UIGraphicsGetCurrentContext()];
 
    // 将当前上下文内容转换为图片对象
    UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
 
    // 关闭图片上下文
    UIGraphicsEndImageContext();
 
    // 将图片保存到本地相册
    UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
}
@end

四、Demo下载:UITouch

Leave a Reply