触摸事件
首先,我们来了解下什么是触摸事件。在iOS中,当用户点击、滑动、捏合等进行操作时,系统会将其转化为触摸事件并发送到应用程序中,应用程序再针对这些事件做出相应的处理。
触摸事件的过程
触摸事件在iOS中可以分为以下几种:
touchesBegan:withEvent:
:手指开始触摸屏幕时调用的方法。touchesMoved:withEvent:
:手指在屏幕上移动时调用的方法。touchesEnded:withEvent:
:手指离开屏幕时调用的方法。touchesCancelled:withEvent:
:由于某种原因(比如来电)导致触摸事件取消时调用的方法。
响应触摸事件
要响应触摸事件,我们需要在视图中重写以下方法:
1
2
3
4
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
这些方法都传入了一个NSSet
类型的参数touches
,该集合包含了所有与此次触摸事件相关的UITouch
对象。我们可以通过UITouch
对象获取触摸点的坐标、时间等信息。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self];
NSLog(@"Touch began at point %@", NSStringFromCGPoint(touchPoint));
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self];
NSLog(@"Touch moved to point %@", NSStringFromCGPoint(touchPoint));
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
CGPoint touchPoint = [touch locationInView:self];
NSLog(@"Touch ended at point %@", NSStringFromCGPoint(touchPoint));
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"Touch cancelled");
}
以下是一个简单的自定义手势识别器示例,它可以检测用户进行的快速滑动操作:
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
@interface FastSwipeGestureRecognizer : UIGestureRecognizer
@end
@implementation FastSwipeGestureRecognizer {
CGPoint _startPoint;
NSTimeInterval _startTime;
}
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = [touches anyObject];
_startPoint = [touch locationInView:self.view];
_startTime = touch.timestamp;
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
// 如果手指移动的距离超过了设定的阈值,则认为是快速滑动
UITouch *touch = [touches anyObject];
CGPoint currentPoint = [touch locationInView:self.view];
CGFloat distance = fabs(currentPoint.x - _startPoint.x);
NSTimeInterval duration = touch.timestamp - _startTime;
if (distance > 100 && duration < 0.3) {
self.state = UIGestureRecognizerStateRecognized;
}
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
self.state = UIGestureRecognizerStateFailed;
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
self.state = UIGestureRecognizerStateFailed;
}
@end
多点触摸
除了单点触摸外,iOS还支持多点触摸。多点触摸指的是同时有两个或以上的触摸点。对于多点触摸,我们需要在UIView子类中重写以下方法:
1
2
3
4
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
这些方法中,touches
参数中包含了所有的UITouch
对象,我们可以遍历这些对象来获取每个触摸点的位置信息。例如:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint touchPoint = [touch locationInView:self];
NSLog(@"Touch began at point %@", NSStringFromCGPoint(touchPoint));
}
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint touchPoint = [touch locationInView:self];
NSLog(@"Touch moved to point %@", NSStringFromCGPoint(touchPoint));
}
}
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
for (UITouch *touch in touches) {
CGPoint touchPoint = [touch locationInView:self];
NSLog(@"Touch ended at point %@", NSStringFromCGPoint(touchPoint));
}
}
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
NSLog(@"Touches cancelled");
}
手势识别
除了基本的触摸事件外,iOS系统还提供了一套手势识别机制。通过手势识别,我们可以轻松实现各种复杂的交互效果,例如拖动、缩放、旋转等。iOS系统内置了多种手势,包括点击、双击、长按、拖动、捏合、旋转等。
iOS系统提供了许多常用的手势识别器,包括:
UITapGestureRecognizer
:敲击手势。UIPinchGestureRecognizer
:缩放手势。UIRotationGestureRecognizer
:旋转手势。UISwipeGestureRecognizer
:轻扫手势。UIPanGestureRecognizer
:拖拽手势。UILongPressGestureRecognizer
:长按手势。
响应手势
要响应手势,我们需要创建一个手势识别器,并将其添加到视图上。手势识别器会根据用户的操作自动触发相应的方法。
下面是一些常用的手势识别器及其使用示例:
点击手势识别器
1
2
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
[self.view addGestureRecognizer:tapGesture];
双击手势识别器
1
2
3
UITapGestureRecognizer *doubleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleDoubleTap:)];
doubleTapGesture.numberOfTapsRequired = 2;
[self.view addGestureRecognizer:doubleTapGesture];
长按手势识别器
1
2
UILongPressGestureRecognizer *longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
[self.view addGestureRecognizer:longPressGesture];
拖动手势识别器
1
2
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
[self.view addGestureRecognizer:panGesture];
捏合手势识别器
1
2
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)];
[self.view addGestureRecognizer:pinchGesture];
旋转手势识别器
1
2
UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(handleRotation:)];
[self.view addGestureRecognizer:rotationGesture];
以下示例创建了一个拖动手势识别器,并将其添加到视图上。每当用户进行拖动操作时,handlePan:
方法会被自动调用。在该方法中,我们获取手势的移动距离,并将视图的位置偏移相应的距离,从而实现了拖动效果。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
- (void)viewDidLoad {
[super viewDidLoad];
// 创建一个拖动手势识别器
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
// 将手势识别器添加到视图上
[self.view addGestureRecognizer:panGesture];
}
- (void)handlePan:(UIPanGestureRecognizer *)gesture {
CGPoint translation = [gesture translationInView:self.view];
gesture.view.center = CGPointMake(gesture.view.center.x + translation.x, gesture.view.center.y + translation.y);
[gesture setTranslation:CGPointZero inView:self.view];
}
自定义手势识别器
除了系统提供的手势识别器外,我们还可以自定义手势识别器来实现各种复杂的手势操作,例如双指旋转、三指拖拽等。自定义手势识别器需要继承UIGestureRecognizer
类,并重写几个方法:
touchesBegan:withEvent:
:手指开始触摸屏幕时调用的方法。touchesMoved:withEvent:
:手指在屏幕上移动时调用的方法。touchesEnded:withEvent:
:手指离开屏幕时调用的方法。touchesCancelled:withEvent:
:由于某种原因(比如来电)导致触摸事件取消时调用的方法。reset
:重置手势状态的方法。shouldBeRequiredToFailByGestureRecognizer:
:返回一个布尔值,表示本手势是否应该由参数手势识别器阻止。shouldReceiveTouch:
:返回一个布尔值,表示本手势是否应该接收指定的触摸事件。
以下示例演示如何使用复合手势识别器实现旋转缩放效果:
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
- (void)viewDidLoad {
[super viewDidLoad];
// 创建一个捏合手势识别器
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)];
[self.view addGestureRecognizer:pinchGesture];
// 创建一个旋转手势识别器
UIRotationGestureRecognizer *rotationGesture = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(handleRotation:)];
[self.view addGestureRecognizer:rotationGesture];
}
- (void)handlePinch:(UIPinchGestureRecognizer *)gesture {
if (gesture.state == UIGestureRecognizerStateChanged) {
gesture.view.transform = CGAffineTransformScale(gesture.view.transform, gesture.scale, gesture.scale);
gesture.scale = 1;
}
}
- (void)handleRotation:(UIRotationGestureRecognizer *)gesture {
if (gesture.state == UIGestureRecognizerStateChanged) {
gesture.view.transform = CGAffineTransformRotate(gesture.view.transform, gesture.rotation);
gesture.rotation = 0;
}
}
图片浏览器示例
在这个示例中,我们将实现以下功能:
- 双击放大/缩小图片。
- 拖拽图片查看不同部位。
- 双指捏合缩放图片。
- 单击隐藏/显示导航栏。
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
99
100
101
102
#import "ViewController.h"
@interface ViewController ()<UIScrollViewDelegate>
@property (nonatomic, strong) UIScrollView *scrollView;
@property (nonatomic, strong) UIImageView *imageView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
self.navigationItem.title = @"hello";
// 创建UIScrollView对象并设置其代理
self.scrollView = [[UIScrollView alloc] initWithFrame:self.view.bounds];
self.scrollView.delegate = self;
self.scrollView.maximumZoomScale = 3.0f;
self.scrollView.minimumZoomScale = 1.0f;
[self.view addSubview:self.scrollView];
// 创建UIImageView对象并添加到UIScrollView上
UIImage *image = [UIImage imageNamed:@"image.png"];
self.imageView = [[UIImageView alloc] initWithImage:image];
self.imageView.userInteractionEnabled = YES;
[self.scrollView addSubview:self.imageView];
// 添加单击手势识别器
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapAction:)];
[self.imageView addGestureRecognizer:tapGesture];
// 添加双击手势识别器
UITapGestureRecognizer *doubleTapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTapAction:)];
doubleTapGesture.numberOfTapsRequired = 2;
[self.imageView addGestureRecognizer:doubleTapGesture];
// 添加拖拽手势识别器和捏合手势识别器
UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panAction:)];
[self.imageView addGestureRecognizer:panGesture];
UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchAction:)];
[self.imageView addGestureRecognizer:pinchGesture];
}
#pragma mark - UIScrollViewDelegate
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return self.imageView;
}
#pragma mark - Gesture Recognizer Actions
// 响应单击手势
- (void)tapAction:(UITapGestureRecognizer *)gesture {
BOOL hidden = !self.navigationController.navigationBarHidden;
[self.navigationController setNavigationBarHidden:hidden animated:YES];
}
- (void)doubleTapAction:(UITapGestureRecognizer *)gesture {
CGFloat zoomScale = self.scrollView.zoomScale;
if (zoomScale == 1.0f) {
zoomScale = 2.0f;
} else {
zoomScale = 1.0f;
}
CGRect zoomRect = [self zoomRectForScale:zoomScale withCenter:[gesture locationInView:gesture.view]];
[self.scrollView zoomToRect:zoomRect animated:YES];
}
- (void)panAction:(UIPanGestureRecognizer *)gesture {
CGPoint translation = [gesture translationInView:self.imageView];
CGPoint center = self.imageView.center;
center.x += translation.x;
center.y += translation.y;
self.imageView.center = center;
[gesture setTranslation:CGPointZero inView:self.imageView];
}
- (void)pinchAction:(UIPinchGestureRecognizer *)gesture {
CGFloat scale = gesture.scale;
self.imageView.transform = CGAffineTransformScale(self.imageView.transform, scale, scale);
gesture.scale = 1.0f;
}
#pragma mark - Helper Methods
- (CGRect)zoomRectForScale:(CGFloat)scale withCenter:(CGPoint)center {
CGRect zoomRect;
zoomRect.size.height = self.scrollView.frame.size.height / scale;
zoomRect.size.width = self.scrollView.frame.size.width / scale;
zoomRect.origin.x = center.x - (zoomRect.size.width / 2.0);
zoomRect.origin.y = center.y - (zoomRect.size.height / 2.0);
return zoomRect;
}
@end