iOS——UIGestureRecognizer

一、概述


1. 概念介绍

UIGestureRecognizer 类是一个抽象类,定义了基本手势的所有行为,但是不能直接使用 UIGestureRecognizer 类,而是要使用它的子类,如下

    UITapGestureRecognizer(点击)

    UILongPressGestureRecognizer(长按)

    UIPanGestureRecognizer(拖动)

    UISwipeGestureRecognizer(轻扫)

    UIRotationGestureRecognizer(旋转)

    UIPinchGestureRecognizer(捏合,用于缩放)


2. 使用

在使用 UIGestureRecognizer 子类对象时,除了要为其设置 目标-动作 对,还要将该子类对象 “附着” 在某个视图上,当该子类对象根据当前附着的视图所发生的触摸事件识别出相应的手势后,就会向指定的目标对象发送指定的动作消息

由 UIGestureRecognizer 对象发出的动作消息都遵循以下规范

    - (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 抽象类


属性

1. 手势状态

// 获取当前手势的状态

@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;


8. 触摸点的个数(同时触摸屏幕的手指)

@property(nonatomic,readonly)NSUInteger numberOfTouches;


方法

1. 初始化 UIGestureRecognizer 对象并添加 目标-动作对,指定初始化方法

- (instancetype)initWithTarget:(nullableid)target action:(nullableSEL)action;


2. 为 UIGestureRecognizer 对象添加 目标-动作对

- (void)addTarget:(id)target action:(SEL)action;


3. 从 UIGestureRecognizer 对象删除 目标-动作对

- (void)removeTarget:(nullableid)target action:(nullableSEL)action;


4. 指定消息的接受者手势对象 必须等到 otherGestureRecognizer 对象失败才会执行

此方法是同时触发多个手势使用其中之一的解决办法 

- (void)requireGestureRecognizerToFail:(UIGestureRecognizer *)otherGestureRecognizer;


5. 获取在指定视图上触摸的位置

- (CGPoint)locationInView:(nullableUIView*)view;


6. 获取手指相对于 指定视图的位置

方法中的 touchIndex 时手指的序号,例如 : 有两个手指触摸屏幕,对于先触摸的手指,系统会对其标号为0,后一个标号为1 

- (CGPoint)locationOfTouch:(NSUInteger)touchIndex inView:(nullableUIView*)view;



三、UIGestureRecognizerDelegate


1. 开始识别 UIGestureRecognizer 对象时调用的方法,返回 NO 则识别结束,不再触发手势
可用于 在控件指定位置使用手势识别

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer;


2. 手指触摸屏幕后回调的方法,返回 NO 则不再进行手势识别、触摸事件,默认返回 YES
此方法在 UIWindow 对象有触摸事件发生时,调用 touchesBegan:withEvent: 之前被调用,如果返回 NO,则不会调用 touchesBegan:withEvent: 方法

- (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;


4. 是否支持多手势触发,返回 YES,则可以多个手势一起触发方法,返回 NO 则为互斥,默认返回 NO

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;


5. 返回 YES 时,第一个手势对象和第二个手势对象互斥时,第一个失效

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer;


6. 返回 YES 时,第一个手势对象和第二个手势对象互斥时,第二个失效

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognize *)otherGestureRecognizer;


四、UITapGestureRecognizer

属性

1. 保存 UITapGestureRecognizer 对象能最少识别的点击次数;如果设置为2,意味着必须要连续点击两次才能被识别,默认为 1

@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

属性

1. 保存 UILongPressGestureRecognizer 对象能最少识别的触摸次数,默认为 0;即不需点击,直接长按即可

@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 的状态

UILongPressGestureRecognizer 对象的状态分为三种:
UIGestureRecognizerStateBegan : 当长按开始时手指按下去的时候
UIGestureRecognizerStateChanges : 当在长按过程中移动了手指,在 allowableMovement 的范围中
UIGestureRecognizerStateEnded : 当长按结束时松开手指


示例代码

- (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

属性

1. 保存 UISwipeGestureRecognizer 对象最少能识别的手指个数;默认为 1

@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 状态

当系统识别出 UISwipeGestureRecognizer 手势对象时,会将其状态改变为 UIGestureRecognizerStateBegan

示例代码

- (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 (nonatomicNSUInteger maximumNumberOfTouches


方法

1. 返回 UIPanGestureRecognizer 对象在指定视图中的拖拽位置,返回的是相对坐标点偏移量,即拖动开始时,坐标为0

- (CGPoint)translationInView:(nullableUIView *)view; 


2. 设置 UIPanGestureRecognizer 对象在指定视图中的拖拽位置;通常设置为 CGPointZero,避免累加

- (void)setTranslation:(CGPoint)translation inView:(nullableUIView *)view;


3. 获取当前 UIPanGestureRecognizer 对象在指定视图中的拖拽速度,单位 : 像素/秒

- (CGPoint)velocityInView:(nullableUIView *)view; 


 UIPanGestureRecognizer 的状态

UIGestureRecognizerStateBegan : 当拖拽开始时手指刚触摸到屏幕时
UIGestureRecognizerStateChanged : 当拖拽过程中位置发生变化
UIGestureRecognizerStateEnded : 当拖拽结束时手指离开屏幕

示例代码

- (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];

}










上述代码中,在拖拽手势识别后,状态改变为 UIGestureRecognizerStateBegan,在移动过程中状态改变为 UIGestureRecognizerStateChanged,手指离开屏幕时,状态改变为 UIGestureRecognizerStateEnded;并且在拖拽过程中,会输出当前的相对偏移位置,每一次在动作方法的最后,将相对偏移位置设置为0,避免一直累加

八、UIPinchGestureRecognizer

属性

1. 保存 UIPinchGestureRecognizer 对象的缩放比例

@property (nonatomicCGFloat scale;


2. 获取缩放的速度,单位 : 缩放比/秒

@property (nonatomic,readonly)CGFloat velocity;


UIPinchGestureRecognizer 的状态

UIGestureRecognizerStateBegan : 当手指刚触摸到屏幕时
UIGestureRecognizerStateChanged : 当手指在缩放的过程中
UIGestureRecognizerStateEnded : 当手指离开屏幕时

示例代码

- (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

属性

1. 保存 UIRotationGestureRecognizer 对象的旋转角度

@property (nonatomicCGFloat rotation;


2. 获取 UIRotationGestureRecognizer 对象的旋转速度

@property (nonatomic,readonly)CGFloat velocity; 


UIRotationGestureRecognizer 的状态

UIGestureRecognizerStateBegan : 当手指刚触摸到屏幕时
UIGestureRecognizerStateChanged : 当手指在旋转的过程中
UIGestureRecognizerStateEnded : 当手指离开屏幕时

示例代码

- (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");
        
    }

}



以上代码中,使用两根手指旋转时,触发其动作方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值