一 UITapGestureRecognizer
点击手势的处理器有2个属性:
-
numberOfTapsRequired
点击的次数 -
numberOfTouchesRequired
点击屏幕手指的个数
for (NSInteger i = 1; i < 6; i++) {
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)];
tapRecognizer.numberOfTapsRequired = i;
tapRecognizer.numberOfTouchesRequired = 2;
[self.view addGestureRecognizer:tapRecognizer];
}
上面创建了5个点击手势处理器,如果用2个手指快速点击了屏幕3次,那么会触发3个点击手势处理器的方法(分别是点击屏幕1次,2次,3次对应的手势处理器方法),这里需要特别注意下
- (void)handleTap:(UITapGestureRecognizer *)recognizer
{
NSUInteger touchCount = recognizer.numberOfTouches;
NSUInteger tapCount = recognizer.numberOfTapsRequired;
NSLog(@"手指个数 %d 触摸次数 %d", touchCount, tapCount);
}
二 UIPinchGestureRecognizer
捏合手势处理器也有2个属性
-
scale
比例 -
velocity
速率(scale
变大,velocity
为正;scale
变小,velocity
为负)
可以利用捏合手势处理器来实现图片的缩放功能
- (void)handlePin:(UIPinchGestureRecognizer *)recognizer
{
recognizer.view.transform = CGAffineTransformScale(recognizer.view.transform, recognizer.scale, recognizer.scale);
recognizer.scale = 1;
}
三 UIRotationGestureRecognizer
旋转手势处理器有2个属性
-
rotation
比例(以开始触碰点为基准0,往逆时针方向旋转,rotation变小,往顺时针方向旋转,rotation变大) -
velocity
速率(顺时针旋转为正;逆时针旋转为负)
可以利用旋转手势来实现旋转图片的功能
- (void)handleRotation:(UIRotationGestureRecognizer *)recognizer
{
recognizer.view.transform = CGAffineTransformRotate(recognizer.view.transform, recognizer.rotation);
recognizer.rotation = 0;
}
四 UISwipeGestureRecognizer
轻扫手势处理器有2个属性
-
numberOfTouchesRequired
手指的个数 -
direction
轻扫的方向(虽然该枚举类型定义为NS_OPTIONS
,但是在测试过程中发现在事件处理方法中,如果使用了多个枚举值,则不能有效判断手势的方向,因此如果需要判断多个轻扫手势,则应该是一个方向对应一个手势处理器)
for (NSInteger i = 0; i < 4; i++) {
UISwipeGestureRecognizer *swipeRecognizer = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipe:)];
swipeRecognizer.numberOfTouchesRequired = 1;
swipeRecognizer.direction = 1 << i;
[self.view addGestureRecognizer:swipeRecognizer];
}
- (void)handleSwipe:(UISwipeGestureRecognizer *)recognizer
{
UISwipeGestureRecognizerDirection direction = recognizer.direction;
if (direction == UISwipeGestureRecognizerDirectionLeft) {
NSLog(@"向左");
} else if (direction == UISwipeGestureRecognizerDirectionRight){
NSLog(@"向右");
} else if (direction == UISwipeGestureRecognizerDirectionUp){
NSLog(@"向上");
} else if (direction == UISwipeGestureRecognizerDirectionDown){
NSLog(@"向下");
}
}
五 UIPanGestureRecognizer
UIPanGestureRecognizer
一般用来处理拖动事件,比如拖动一个控件在屏幕上移动
- (void)handlePan:(UIPanGestureRecognizer *)recognizer
{
CGPoint point = [recognizer translationInView:recognizer.view];
recognizer.view.transform = CGAffineTransformTranslate(recognizer.view.transform, point.x, point.y);
[recognizer setTranslation:CGPointZero inView:recognizer.view];
}
六 UILongPressGestureRecognizer
长按手势处理器有两个重要的属性
-
minimumPressDuration
长按所需的最短时间 -
allowableMovement
长按手指能移动的最大距离,超出这个
UILongPressGestureRecognizer *longPressRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handleLongPress:)];
longPressRecognizer.minimumPressDuration = 2;
longPressRecognizer.numberOfTouchesRequired = 2;
longPressRecognizer.allowableMovement = 500;
[self.view addGestureRecognizer:longPressRecognizer];
触发长按手势处理器会调用两次对应的方法(开始一次,结束一次),所以需要特别处理下
- (void)handleLongPress:(UILongPressGestureRecognizer *)recognizer
{
if (recognizer.state == UIGestureRecognizerStateBegan) {
NSLog(@"UILongPressGestureRecognizer Begin");
} else if (recognizer.state == UIGestureRecognizerStateEnded) {
NSLog(@"UILongPressGestureRecognizer End");
}
}
七 自定义手势处理器
- 继承
UIGestureRecognizer
- 引入
#import <UIKit/UIGestureRecognizerSubclass.h>
- 在合适的时候设置
self.state = UIGestureRecognizerStateEnded;
来完成自定义手势处理器
下面的例子设计了一个名叫JCGestureRecognizer
的手势处理器,当符合从左往右滑动200像素并且滑动过程中上下不超过80像素的浮动的情况,触发该手势处理器。
@interface JCGestureRecognizer : UIGestureRecognizer
@end
#import "JCGestureRecognizer.h"
#import <UIKit/UIGestureRecognizerSubclass.h>
@interface JCGestureRecognizer ()
{
CGPoint startPoint;
}
@end
@implementation JCGestureRecognizer
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[super touchesBegan:touches withEvent:event];
if (touches.count > 1) {
self.state = UIGestureRecognizerStateFailed;
return;
}
UITouch *touch = [touches anyObject];
startPoint = [[touches anyObject] locationInView:touch.view];
// self.state = UIGestureRecognizerStateBegan;
}
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[super touchesMoved:touches withEvent:event];
if (touches.count > 1) {
self.state = UIGestureRecognizerStateFailed;
return;
}
UITouch *touch = [touches anyObject];
CGPoint point = [[touches anyObject] locationInView:touch.view];
if (ABS(point.y - startPoint.y) > 80) {
self.state = UIGestureRecognizerStateFailed;
return;
}
if (point.x - startPoint.x > 200) {
self.state = UIGestureRecognizerStateEnded;
}
}
@end
使用
JCGestureRecognizer *jcRecognizer = [[JCGestureRecognizer alloc] initWithTarget:self action:@selector(handleJC:)];
[self.view addGestureRecognizer:jcRecognizer];
- (void)handleJC:(JCGestureRecognizer *)recognizer
{
NSLog(@"JCGestureRecognizer");
}
这里需要特别注意一下,在使用自定义手势的时候,在- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
方法中要非常谨慎的设置self.state = UIGestureRecognizerStateBegan;
,如果在刚刚的示例中我们加上这段代码,那么只要有一小点的位移,都会触发handleJC:
这个方法,并且会多次调用,此时recognizer
的state
为UIGestureRecognizerStateBegan
,这个信息对我们设计的这个手势处理器来说没有任何用处,因此在这里我们没有设置UIGestureRecognizerStateBegan
这个状态,这也给我们一个启发,在手势处理器对应的方法里,首先尽量判断手势的状态,然后根据对应的状态做对应的事情,以免发生不该出现的问题。
八 手势的互斥性
比如我们给一个图片添加了一个旋转手势处理器和缩放手势处理器,在没有特殊处理的情况下,如果旋转了图片,那么就不能缩放;如果缩放了图片,就不能旋转了。但我们想要的效果是同时可以旋转和缩放
解决这个方法需要用到UIGestureRecognizerDelegate
- 设置两个手势处理的委托
pinRecognizer.delegate = self;
rotationRecognizer.delegate = self;
- 在下面的委托方法中返回
YES
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES;
}