iOS触摸事件、手势识别原理

触摸发生时,UIWindow会有一个队列来存放所有的触摸事件,然后再把这些事件发送给对应的hit-test view,hit-test view会通过touch的四个函数来接收这些事件。

四个函数分别为:(began,move, end, cancel)

//touches method

-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

    NSLog(@"%s", __func__);

    [super touchesBegan:touches withEvent:event];

}


- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event

{

NSLog(@"%s", __func__);

    [super touchesMoved:touches withEvent:event];

}


- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event

{

NSLog(@"%s", __func__);

    [super touchesEnded:touches withEvent:event];

}


- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent

*)event {

NSLog(@"%s", __func__);

    [super touchesCancelled:touches withEvent:event];

}

手势识别器同样有touch的四个函数,但是手势识别器本身并不继承自UIResponder,本身并不在响应链里,只有手势识别器对应的view在响应链中的时候手势识别器才会监听touch事件,并根据自己的touch函数识别手势,然后触发相应的回调函数。本质来说,hit-test view触摸事件的回调跟手势识别器是两个独立的过程,互不干涉,手势识别器先开始接收touch事件。但是手势识别中定义了三个属性,能够影响hit-test view触摸事件的调用过程,这三个属性如下所示:


gesture.cancelsTouchesInView

当值为YES时(默认值),表示手势识别成功后触摸事件取消掉,即识别成功后hitTest-View会调用touchesCancelled函数。

当值为NO时,触摸事件会正常起作用,会正常收到touchesEnded消息。


gesture.delaysTouchesBegan  =NO;

当值为NO时(默认值),触摸事件和手势识别的过程同时进行,当然先会发送触摸事件,然后当手势识别成功时,触摸事件会被取消掉,即识别成功后hitTest-View会调用touchesCancelled函数。

当值为YES时,手势识别器先接收touch事件进行手势识别,识别过程中hit-test view的触摸事件会先被UIWindow hold住,当手势识别成功时hit-test view的触摸事件不会调用,当手势识别失败时才开始调用touchesBegan函数。


gesture.delaysTouchesEnded = YES;

此属性差别比较小。

当值为YES时(默认值),当手势识别失败时会延迟(约0.15ms)调用touchesEnded函数。

当值为NO时,当手势识别失败时会立即调用touchesEnded函数。


delaysTouchesBegan、delaysTouchesEnded这两个属性决定是否在手势识别过程中向hit-test view发送触摸事件。


总结:触摸事件与手势识别是两个相对独立的过程,但是手势识别可以通过一些属性来影响触摸事件的调用,一般来说手势识别器的回调函数会比hit-test view的触摸事件的晚一些,因为手势识别器只有在手势识别出来之后才会触发回调函数(默认情况下只有一个手势识别器能够响应),但是手势识别器接收touch事件的时机比hit-test view早。


触摸事件过程:

触摸开始,找到first responder同时找到响应链,当响应链上没有手势识别器时,触摸事件通过first responder的响应链开始传递,如果响应链上有手势识别器,那么手势识别器先接收事件,然后再根据手势识别器的三个属性来决定是否同时将触摸事件传给first responder。


手势识别器原理:

手势识别器根据自身的四个touch函数来识别手势,例如长按、滑动等,手势识别器并不继承自UIResponder,因此它的四个touch函数不是UIResponder中的函数,而是UIResponder中这四个函数的镜像(说白了就是从UIResponder的头文件中复制粘贴过来的)。


由此可以推测UIButton的“按下”事件等也是根据四个Touch函数来实现的,因为UIButton继承自UIResponder,本身自带四个Touch函数。(经实验发现UIButton设置为enable时,在接收到触摸事件之后不会继续向上传递触摸事件,设置为disable时会向上传递触摸事件,但是加在UIButton上的tap手势不会起作用)


以下来自苹果代码注释UIGestureRecognizerSubclass.h:

// mirror of the

touch-delivery methods on UIResponder

//

UIGestureRecognizers aren't in the responder chain, but observe touches

hit-tested to their view and their view's subviews

//

UIGestureRecognizers receive touches before the view to which the touch was

hit-tested

-  (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent

*)event;

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent

*)event;

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent

*)event;

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent

*)event;

你可能感兴趣的:(iOS触摸事件、手势识别原理)