一、概述
1. 概念介绍
UITapGestureRecognizer(点击)
UILongPressGestureRecognizer(长按)
UIPanGestureRecognizer(拖动)
UISwipeGestureRecognizer(轻扫)
UIRotationGestureRecognizer(旋转)
UIPinchGestureRecognizer(捏合,用于缩放)
2. 使用
- (void)action:(UIGestureRecognizer *)gestureRecognizer;
UIGestureRecognizer 对象在识别手势时,会截取本应该由 该UIGestureRecognizer 对象附着的视图自行处理的触摸事件,因此,附着了 UIGestureRecognizer 对象的视图可能不会正常收到 UIResponder 消息,例如 touchesBegan:withEvent: 等
3. UIView(UIViewGestureRecognizers)
// 向一个 UIView对象添加指定的 UIGestureRecognizer手势对象
- (void)addGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer;
// 从一个 UIView对象删除指定的 UIGestureRecognizer手势对象
- (void)removeGestureRecognizer:(UIGestureRecognizer*)gestureRecognizer;
// 询问一个 UIView对象是否执行手势触摸事件,默认返回 YES
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;
二、UIGestureRecognizer 抽象类
属性
// 获取当前手势的状态
@property(nonatomic,readonly)UIGestureRecognizerStatestate;
UIGestureRecognizerState 枚举
typedef NS_ENUM(NSInteger,UIGestureRecognizerState) {
// 尚未识别是何种手势操作(但可能已经触发了触摸事件),默认状态
UIGestureRecognizerStatePossible,
//手势已经开始,此时已经被识别,但是这个过程中可能发生变化,手势操作尚未完成
UIGestureRecognizerStateBegan,
//手势状态发生改变
UIGestureRecognizerStateChanged,
//手势识别操作完成(此时已经松开手指)
UIGestureRecognizerStateEnded,
//手势被取消,恢复到默认状态
UIGestureRecognizerStateCancelled,
//手势识别失败,恢复到默认状态
UIGestureRecognizerStateFailed,
//同 end一样
UIGestureRecognizerStateRecognized =UIGestureRecognizerStateEnded
};
2. 手势识别是否可用
// 默认是 NO
@property(nonatomic,getter=isEnabled)BOOL enabled;
3. 获取触摸手势对象的 UIView 对象
@property(nullable,nonatomic,readonly)UIView *view;
4. 是否取消触摸控件的响应
默认是 YES,此时 当手势识别器识别到相应手势时,会向触摸到的 UIView 对象发送 touchesCancelled:withEcent: 消息以取消 UIView 对象对 UITouch 对象的相应,此时只有 手势识别器 响应 UITouch 对象;当设置为 NO 时,手势识别器识别到相应的手势时不会向触摸到的 UIView 对象发送 touchesCancelld:withEvent: 消息,此时 UIView 对象和 手势识别器 均响应 UITouch 对象
手势识别和触摸事件是同时存在的,只是因为 touchesCancelled:withEvent: 方法导致 触摸事件失效
@property(nonatomic)BOOL cancelsTouchesInView;
5. 是否延迟发送触摸事件给触摸到的对象
默认是 NO,此时 当触摸到 UIView 对象时,手势识别器 先捕捉到 UITouch 对象,然后发送给 触摸事件,即 手势识别器和触摸事件共享 UITouch 对象;当设置为 YES 时,手势识别器在识别过程中,不会发送给 触摸事件,即 UIView 对象不会响应触摸事件,只有在识别失败时,才会给触摸的 UIView 对象发送触摸开始事件,此时会延迟 0.15ms 再发送
@property(nonatomic)BOOL delaysTouchesBegan;
6. 触摸识别失败是否立即结束本次手势识别的触摸事件
默认为 YES,此时 发生一个触摸时,在手势识别成功后,发送 touchesCancelled:withEvent: 消息给 触摸的 UIView 对象,手势识别失败时,会延迟 0.15ms 左右,期间没有接受到 别的触摸才会发送 touchesEnded:withEvent: 结束触摸;当设置为 NO 时,则不会延迟,会立即发送 touchesEnded:withEvent: 消息结束触摸
@property(nonatomic)BOOL delaysTouchesEnded;
7. UIGestureRecognizer 代理
@property(nullable,nonatomic,weak)id <UIGestureRecognizerDelegate> delegate;
@property(nonatomic,readonly)NSUInteger numberOfTouches;
方法
- (instancetype)initWithTarget:(nullableid)target action:(nullableSEL)action;
2. 为 UIGestureRecognizer 对象添加 目标-动作对
- (void)addTarget:(id)target action:(SEL)action;
- (void)removeTarget:(nullableid)target action:(nullableSEL)action;
此方法是同时触发多个手势使用其中之一的解决办法
- (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer;
- (CGPoint)locationInView:(nullableUIView*)view;
方法中的 touchIndex 时手指的序号,例如 : 有两个手指触摸屏幕,对于先触摸的手指,系统会对其标号为0,后一个标号为1
- (CGPoint)locationOfTouch:(NSUInteger)touchIndex inView:(nullableUIView*)view;
三、UIGestureRecognizerDelegate
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
// 解决 UITapGestureRecognizer 对象和 UIButton 对象冲突
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass:[UIButton class]]) {
return NO;
}
return YES;
}
3. 手指按压屏幕后回调的方法,返回 NO 则不再进行手势识别、触摸事件等
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceivePress:(UIPress *)press;
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
6. 返回 YES 时,第一个手势对象和第二个手势对象互斥时,第二个失效
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognize *)otherGestureRecognizer;
四、UITapGestureRecognizer
属性
@property (nonatomic)NSUInteger numberOfTapsRequired;
2. 保存 UITapGestureRecognizer 对象能最少识别的手指个数;如果设置为2,意味着必须要使用两根手指点击才能被识别,默认为 1
示例代码
- (void)viewDidLoad {
[super viewDidLoad];
UITapGestureRecognizer * tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tap:)];
// 设置 UITapGestureRecognizer 对象能最少识别的点击次数,即连续点击两次才能被识别
tapRecognizer.numberOfTapsRequired = 2;
// 设置 UITapGestureRecognizer 对象能最少识别的触摸个数,即同时用两个手指触摸才能被识别
tapRecognizer.numberOfTouchesRequired = 2;
[self.view addGestureRecognizer:tapRecognizer];
}
- (void)tap:(UIGestureRecognizer *)gestureRecognizer {
NSLog(@"tap!");
}
上述代码必须通过两根手指连续点击两次屏幕才会触发动作方法,输出 tap!
五、UILongPressGestureRecognizer
属性
@property (nonatomic)NSUInteger numberOfTapsRequired;
2. 保存 UILongPressGestureRecognizer 对象能最少是被的手指个数,默认为 1
@property (nonatomic)NSUInteger numberOfTouchesRequired
3. 保存 UILongPressGestureRecognizer 对象识别长按手势的最短时间;默认为 0.5s
@property (nonatomic)CFTimeInterval minimumPressDuration;
4. 保存 UILongPressGestureRecognizer 对象识别长按手势时可移动的范围,单位 : 像素;默认为 10
@property (nonatomic)CGFloat allowableMovement;
UILongPressGestureRecognizer 的状态
示例代码
- (void)longPressMethod {
UILongPressGestureRecognizer * longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPress:)];
// UILongPressGestureRecognizer 对象最少能识别的手指个数
longPressRecognizer.numberOfTouchesRequired = 2;
// UILongPressGestureRecognizer 对象最少能识别的触摸次数
longPressRecognizer.numberOfTapsRequired = 1;
// UILongPressGestureRecognizer 对象识别长按手势的最短时间
longPressRecognizer.minimumPressDuration = 0.5;
// UILongPressGestureRecognizer 对象识别时允许移动的最大距离
longPressRecognizer.allowableMovement = 10;
[self.view addGestureRecognizer:longPressRecognizer];
}
- (void)longPress:(UIGestureRecognizer *)gestureRecognizer {
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
NSLog(@"长按开始");
}
else if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
NSLog(@"长按结束");
}
else if (gestureRecognizer.state == UIGestureRecognizerStateChanged) {
NSLog(@"长按位置改变");
}
}
UIGestureRecognizerStateChanged
六、UISwipeGestureRecognizer
属性
@property(nonatomic)NSUInteger numberOfTouchesRequired
2. 保存 UISwipeGestureRecognizer 对象的手势方向;默认为 UISwipeGestureRecognizerDirectionRight
@property(nonatomic)UISwipeGestureRecognizerDirection direction;
UISwipeGestureRecognizer 枚举
typedef NS_OPTIONS(NSUInteger, UISwipeGestureRecognizerDirection) {
UISwipeGestureRecognizerDirectionRight = 1 << 0,// 向右滑
UISwipeGestureRecognizerDirectionLeft = 1 << 1,// 向左滑
UISwipeGestureRecognizerDirectionUp = 1 << 2,// 向上滑
UISwipeGestureRecognizerDirectionDown = 1 << 3// 向下滑
};
注意 : 在设置 UISwipeGestureRecognizer 对象的手势方向时,只能同时设置 水平或垂直 中的一个,不能同时既设置水平方向,也设置垂直方向;例如 : UISwipeGestureRecognizerDirectionRight | UISwipeGestureRecognizerDirectionUp
UISwipeGestureRecognizer 状态
示例代码
- (void)swipeMethod {
UISwipeGestureRecognizer * swipeLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe:)];
// direction 属性设置时,只能同时使用水平方向或垂直方向,不能两个方向都使用
swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
[self.view addGestureRecognizer:swipeLeft];
UISwipeGestureRecognizer * swipeRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe:)];
// direction 属性设置时,只能同时使用水平方向或垂直方向,不能两个方向都使用
swipeRight.direction = UISwipeGestureRecognizerDirectionRight;
[self.view addGestureRecognizer:swipeRight];
UISwipeGestureRecognizer * swipeUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe:)];
// direction 属性设置时,只能同时使用水平方向或垂直方向,不能两个方向都使用
swipeUp.direction = UISwipeGestureRecognizerDirectionUp;
[self.view addGestureRecognizer:swipeUp];
UISwipeGestureRecognizer * swipeDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(swipe:)];
// direction 属性设置时,只能同时使用水平方向或垂直方向,不能两个方向都使用
swipeDown.direction = UISwipeGestureRecognizerDirectionDown;
[self.view addGestureRecognizer:swipeDown];
}
- (void)swipe:(UISwipeGestureRecognizer *)gestureRecognizer {
if (gestureRecognizer.direction == UISwipeGestureRecognizerDirectionUp) {
NSLog(@"向上滑");
}
else if (gestureRecognizer.direction == UISwipeGestureRecognizerDirectionDown) {
NSLog(@"向下滑");
}
else if (gestureRecognizer.direction == UISwipeGestureRecognizerDirectionLeft) {
NSLog(@"向左滑");
}
else if (gestureRecognizer.direction == UISwipeGestureRecognizerDirectionRight) {
NSLog(@"向右滑");
}
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
NSLog(@"swipe began");
}
}
上述代码的动作方法中的参数类型为 UISwipeGestureRecognizer,方便判断手势的方向;且手势识别后状态改变为 UIGestureRecognizerStateBegan
七、UIPanGestureRecognizer
属性
1. 保存 UIPanGestureRecognizer 对象能最少识别的手指个数;默认为 1@property (nonatomic) NSUInteger minimumNumberOfTouches
2. 保存 UIPanGestureRecognizer 对象能最大识别的手指个数;默认为 UINT_MAX 无限大
@property (nonatomic) NSUInteger maximumNumberOfTouches
方法
1. 返回 UIPanGestureRecognizer 对象在指定视图中的拖拽位置,返回的是相对坐标点偏移量,即拖动开始时,坐标为0
- (CGPoint)translationInView:(nullableUIView *)view;
2. 设置 UIPanGestureRecognizer 对象在指定视图中的拖拽位置;通常设置为 CGPointZero,避免累加
- (void)setTranslation:(CGPoint)translation inView:(nullableUIView *)view;
- (CGPoint)velocityInView:(nullableUIView *)view;
UIPanGestureRecognizer 的状态
示例代码
- (void)panMethod {
UIPanGestureRecognizer * panRecignizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)];
// UIPanGestureRecognizer 对象最少识别的手指个数,默认为 1
panRecignizer.minimumNumberOfTouches = 1;
// UIPanGestureRecognizer 对象最少识别的手指个数,默认为 UNIT_MAX 无限大
panRecignizer.maximumNumberOfTouches = 10;
[self.view addGestureRecognizer:panRecignizer];
}
- (void)pan:(UIPanGestureRecognizer *)gestureRecignozer {
if (gestureRecignozer.state == UIGestureRecognizerStateBegan) {
NSLog(@"开始移动");
}
else if (gestureRecignozer.state == UIGestureRecognizerStateChanged) {
// 获取在指定视图中的拖拽位置,返回的是相对坐标的偏移量,即拖动开始时,坐标为 0
NSLog(@"移动中 : currentPoint is %@", NSStringFromCGPoint([gestureRecignozer translationInView:self.view]));
}
else if (gestureRecignozer.state == UIGestureRecognizerStateEnded) {
NSLog(@"移动结束");
}
// 获取在指定视图中的速度,单位 : 像素/秒
NSLog(@"currentVelocity is %@", NSStringFromCGPoint([gestureRecignozer velocityInView:self.view]));
// 设置在指定视图中拖拽的坐标为 0
[gestureRecignozer setTranslation:CGPointZero inView:self.view];
}
八、UIPinchGestureRecognizer
属性
@property (nonatomic) CGFloat scale;
2. 获取缩放的速度,单位 : 缩放比/秒
@property (nonatomic,readonly)CGFloat velocity;
UIPinchGestureRecognizer 的状态
示例代码
- (void)pinchMethod {
UIPinchGestureRecognizer * pinchRecignizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinch:)];
// 设置缩放比例
pinchRecignizer.scale = 1.0;
[self.view addGestureRecognizer:pinchRecignizer];
}
- (void)pinch:(UIGestureRecognizer *)gestureRecogizer {
if (gestureRecogizer.state == UIGestureRecognizerStateBegan) {
NSLog(@"pinch start");
}
else if (gestureRecogizer.state == UIGestureRecognizerStateChanged) {
NSLog(@"pinch changed");
}
else if (gestureRecogizer.state == UIGestureRecognizerStateEnded) {
NSLog(@"pinch ended");
}
}
九、UIRotationGestureRecognizer
属性
@property (nonatomic) CGFloat rotation;
2. 获取 UIRotationGestureRecognizer 对象的旋转速度
@property (nonatomic,readonly)CGFloat velocity;
UIRotationGestureRecognizer 的状态
示例代码
- (void)rotationMethod {
UIRotationGestureRecognizer * rotationRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(rotation:)];
// 旋转的角度
rotationRecognizer.rotation = 60;
[self.view addGestureRecognizer:rotationRecognizer];
}
- (void)rotation:(UIGestureRecognizer *)gestureRecognizer {
if (gestureRecognizer.state == UIGestureRecognizerStateBegan) {
NSLog(@"rotation start");
}
else if (gestureRecognizer.state == UIGestureRecognizerStateChanged) {
NSLog(@"rotation changed");
}
else if (gestureRecognizer.state == UIGestureRecognizerStateEnded) {
NSLog(@"rotation ended");
}
}