一. 监听触摸事件的做法
如果想监听一个view上面的触摸事件,不使用手势实现的步骤
(1). 自定义一个view
(2). 实现view的touches方法,在方法内部实现具体处理代码通过touches方法监听view触摸事件,有很明显的几个缺点
(1). 必须得自定义view
(2). 由于是在view内部的touches方法中监听触摸事件,因此默认情况下,无法让其他外界对象监听view的触摸事件
(3). 不容易区分用户的具体手势行为iOS 3.2之后,苹果推出了手势识别功能(Gesture Recognizer),在触摸事件处理方面,大大简化了开发者的开发难度
二. 手势识别器简介
为了完成手势识别,必须借助于手势识别器:UIGestureRecognizer
利用UIGestureRecognizer,能轻松识别用户在某个view上面做的一些常见手势
UIGestureRecognizer是一个抽象类,定义了所有手势的基本行为,使用它的子类才能处理具体的手势
UIGestureRecognizer的子类
UITapGestureRecognizer(敲击)
UIPinchGestureRecognizer(捏合,用于缩放)
UIPanGestureRecognizer(拖拽)
UISwipeGestureRecognizer(轻扫)
UIRotationGestureRecognizer(旋转)
UILongPressGestureRecognizer(长按)
三. UIGestureRecognizer的常见属性和方法
UIGestureRecognizer继承于NSObject
// 初始化手势要触发的对象与事件
- (instancetype)initWithTarget:(nullable id)target action:(nullable SEL)action
// 添加手势要触发的对象与事件
- (void)addTarget:(id)target action:(SEL)action;
// 移除手势要触发的对象与事件
- (void)removeTarget:(nullable id)target action:(nullable SEL)action;
// 手势状态
@property(nonatomic,readonly) UIGestureRecognizerState state;
// 代理
@property(nullable,nonatomic,weak) id <UIGestureRecognizerDelegate> delegate;
// 手势是否可用,默认YES
@property(nonatomic, getter=isEnabled) BOOL enabled;
// 只读,手势所属的视图
@property(nullable, nonatomic,readonly) UIView *view;
// 默认YES.意思就是说一旦手势被识别,那么就调用[touchView touchesCancelled:withEvent]
@property(nonatomic) BOOL cancelsTouchesInView;
// 默认NO.意思就是再手势识别成功之前,touchObj还是要分发到touchView.
// 设置为YES的时候就表示从手势识别成功之前touchObj不给touchView分发
@property(nonatomic) BOOL delaysTouchesBegan;
// 默认YES:在手势识别成功之前,touchesEnded不会被调用。
// 设置为NO:在手势识别成功之前,touchesEnded会被调用
@property(nonatomic) BOOL delaysTouchesEnded;
// 当指定的识别器(调用者)识别失败,才去识别另一个识别器otherGestureRecognizer
- (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer;
// 获取手势识别器的触摸点
- (CGPoint)locationInView:(nullable UIView*)view;
// 获取手势识别器的触摸点个数
- (NSUInteger)numberOfTouches;
// 指定触摸点的位置
- (CGPoint)locationOfTouch:(NSUInteger)touchIndex inView:(nullable UIView*)view;
四. UIGestureRecognizer代理
注意: 使用多个手势必须使用代理
// 是否允许触发手势
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;
// 是否允许多个同时支持多个手势,默认不允许,手势必须要设置代理
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;
// 这个方法在这两个gesture recognizers中的任意一个将堵塞另一个的触摸事件时调用,
// 如果返回YES,则两个gesture recognizers可同时识别,
// 如果返回NO,则并不保证两个gesture recognizers必不能同时识别,
// 因为另外一个gesture recognizer的此方法可能返回YES。
// 也就是说两个gesture recognizers的delegate方法只要任意一个返回YES,则这两个就可以同时识别;
// 只有两个都返回NO的时候,才是互斥的。默认情况下是返回NO
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer NS_AVAILABLE_IOS(7_0);
// 是否允许手势识别器识别失败的时候使用另一个识别器otherGestureRecognizer
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer NS_AVAILABLE_IOS(7_0);
// 是否允许接收触摸点
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch;
// 是否允许接收长按点
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceivePress:(UIPress *)press;
五. UIGestureRecognizer的子类常见属性和方法
1. UITapGestureRecognizer(敲击)
// 需要连续敲击几次才可触发,默认1次
@property (nonatomic) NSUInteger numberOfTapsRequired;
// 需要几根手指一起敲击才可触发,默认1根
@property (nonatomic) NSUInteger numberOfTouchesRequired __TVOS_PROHIBITED;
2. UIPinchGestureRecognizer(捏合,用于缩放)
提示: 模拟器快捷键:opsin + shift 向上拖“两个触摸点”
// 缩放比例
@property (nonatomic) CGFloat scale;
// 缩放速度
@property (nonatomic,readonly) CGFloat velocity;
3. UIPanGestureRecognizer(拖拽)
// 拖动的最短距离
@property (nonatomic) NSUInteger minimumNumberOfTouches __TVOS_PROHIBITED;
// 拖动的最长距离
@property (nonatomic) NSUInteger maximumNumberOfTouches __TVOS_PROHIBITED;
// 在指定的view上得坐标
- (CGPoint)translationInView:(nullable UIView *)view;
// 设置在view中移动以后的坐标为translation
- (void)setTranslation:(CGPoint)translation inView:(nullable UIView *)view;
// 拖动view,返回的值就用于计算view相对于父控件拖动的速度
- (CGPoint)velocityInView:(nullable UIView *)view;
4. UISwipeGestureRecognizer(轻扫)
// 需要几根手指一起轻扫才可触发,默认1根
@property(nonatomic) NSUInteger numberOfTouchesRequired __TVOS_PROHIBITED;
// 设置轻扫方向
@property(nonatomic) UISwipeGestureRecognizerDirection direction;
5. UIRotationGestureRecognizer(旋转)
// 旋转角度
@property (nonatomic) CGFloat rotation;
// 旋转速度
@property (nonatomic,readonly) CGFloat velocity;
6. UILongPressGestureRecognizer(长按)
注意: 长安手势一般会触发两次,所有一般为了只做一次,要做一次判断
// 需要连续长按几次才可触发,默认0次
@property (nonatomic) NSUInteger numberOfTapsRequired;
// 需要几根手指一起长按才可触发,默认1根
@property (nonatomic) NSUInteger numberOfTouchesRequired __TVOS_PROHIBITED;
// 最小长按时间
@property (nonatomic) CFTimeInterval minimumPressDuration;
// 允许移动距离
@property (nonatomic) CGFloat allowableMovement;
六. 手势的具体使用
#import "ViewController.h"
@interface ViewController () <UIGestureRecognizerDelegate>
@property (weak, nonatomic) IBOutlet UIImageView *imageView;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
[self setUpTap];
[self setUpLongPress];
[self setUpSwipe];
[self setUpRotation];
[self setUpPinch];
[self setUpPan];
}
#pragma mark - 点按手势
- (void)setUpTap {
UITapGestureRecognizer *gestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(actionUpTap)];
// 多个手势必须要代理
gestureRecognizer.delegate = self;
[_imageView addGestureRecognizer:gestureRecognizer];
}
- (void)actionUpTap {
NSLog(@"点按手势");
}
#pragma mark - 长按手势
- (void)setUpLongPress {
UILongPressGestureRecognizer *gestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(actionLongPress)];
gestureRecognizer.delegate = self;
[_imageView addGestureRecognizer:gestureRecognizer];
}
- (void)actionLongPress {
NSLog(@"长按手势");
}
#pragma mark - 轻扫手势
- (void)setUpSwipe{
// 默认向右轻扫,如果要同时有多个轻扫方向,必须要创建轻扫对象
UISwipeGestureRecognizer *gestureRecognizerRight = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(actionSwipe)];
[_imageView addGestureRecognizer:gestureRecognizerRight];
UISwipeGestureRecognizer *gestureRecognizerLeft = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(actionSwipe)];
// 向左轻扫
gestureRecognizerLeft.direction = UISwipeGestureRecognizerDirectionLeft;
[_imageView addGestureRecognizer:gestureRecognizerLeft];
UISwipeGestureRecognizer *gestureRecognizerUp = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(actionSwipe)];
// 向上轻扫
gestureRecognizerUp.direction = UISwipeGestureRecognizerDirectionUp;
[_imageView addGestureRecognizer:gestureRecognizerUp];
UISwipeGestureRecognizer *gestureRecognizerDown = [[UISwipeGestureRecognizer alloc] initWithTarget:self action:@selector(actionSwipe)];
// 向下轻扫
gestureRecognizerDown.direction = UISwipeGestureRecognizerDirectionDown;
[_imageView addGestureRecognizer:gestureRecognizerDown];
}
- (void)actionSwipe {
NSLog(@"轻扫手势");
}
#pragma mark - 旋转手势
- (void)setUpRotation {
UIRotationGestureRecognizer *gestureRecognizer = [[UIRotationGestureRecognizer alloc] initWithTarget:self action:@selector(actionRotation:)];
gestureRecognizer.delegate = self;
[_imageView addGestureRecognizer:gestureRecognizer];
}
- (void)actionRotation:(UIRotationGestureRecognizer *)rotation {
_imageView.transform = CGAffineTransformRotate(_imageView.transform, rotation.rotation);
// 复位
rotation.rotation = 0;
}
#pragma mark - 捏合手势
- (void) setUpPinch {
UIPinchGestureRecognizer *gestureRecognizer = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(actionPinch:)];
gestureRecognizer.delegate = self;
[_imageView addGestureRecognizer:gestureRecognizer];
}
- (void)actionPinch:(UIPinchGestureRecognizer *)pinch {
_imageView.transform = CGAffineTransformScale(_imageView.transform, pinch.scale, pinch.scale);
// 复位
pinch.scale = 1;
}
#pragma mark - 拖拽手势
- (void)setUpPan {
UIPanGestureRecognizer *gestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(actionPan:)];
gestureRecognizer.delegate = self;
[_imageView addGestureRecognizer:gestureRecognizer];
}
- (void)actionPan:(UIPanGestureRecognizer *)pan {
//NSLog(@"%ld",[pan numberOfTouches]);
// 获取手势的触摸点
// CGPoint curP = [pan locationInView:self.imageView];
CGPoint panTrans = [pan translationInView:_imageView];
_imageView.transform = CGAffineTransformTranslate(_imageView.transform, panTrans.x, panTrans.y);
// 复位
[pan setTranslation:CGPointZero inView:_imageView];
}
#pragma mark - 手势代理
// 是否允许多个同时支持多个手势,默认不允许,手势必须要设置代理
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
// 是否允许触发手势事件
- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer {
return YES;
}
// 是否允许接收触摸点
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
return YES;
}
@end