美文网首页
GestureRecognizers与触摸事件分发

GestureRecognizers与触摸事件分发

作者: 默默_David | 来源:发表于2017-04-25 09:51 被阅读171次

一.Gesture Recognizers

Gesture

Recognizers是在iOS3.2引入的,可以用来识别手势、简化定制视图事件处理的对象。GestureRecognizers的基类为UIGestureRecognizer,这一个抽象基类,定义了实现底层手势识别行为的编程接口。在UIKit框架中提供了6个具体的手势识别类,用来识别常见的手势。这6个手势识别器类为:

UITapGestureRecognizer:用来识别点击手势,包括单击,双击,甚至三击等。

UIPinchGestureRecognizer:用来识别手指捏合手势。

UIPanGestureRecognizer:用来识别拖动手势。

UISwipeGestureRecognizer:用来识别Swipe手势。

UIRotationGestureRecognizer:用来识别旋转手势。

UILongPressGestureRecognizer:用来识别长按手势。

为了识别手势,需要将Gesture Recognizers关联到其检测触摸事件的view上,可以使用UIView的addGestureRecognizer:方法将手势识别器绑定到视图上。GestureRecognizers在触摸事件处理流程中,处于观察者的角色,其不是view层级结构的一部分,所以也不参与responderchain。在将触摸事件发送给hit-test view之前,系统会先将触摸事件发送到hit-testview上绑定的或hit-test view父视图(superview)上绑定的GestureRecognizers上。其流程大概如下图所示:

注:图中view与Gesture Recognizer的关系是,GestureRecognizer关联在view或view的superview(可能多级)上。

二.Gesture Recognizers与事件分发路径的关系

Gesture

Recognizers可能会延迟将触摸事件发送到hit-test

view上,默认情况下,当GestureRecognizers识别到手势后,会向hit-test

view发送cancel消息,来取消之前发给hit-testview的事件。控制这个流程的是UIGestureRecognizer的三个属性

cancelsTouchesInView (默认为YES)

delaysTouchesBegan (默认为NO)

delaysTouchesEnded (默认为YES)

cancelsTouchesInView为YES,表示当GestureRecognizers识别到手势后,会向hit-test

view发送touchesCancelled:withEvent:消息来取消hit-test

view对此触摸序列的处理,这样只有GestureRecognizers能响应此触摸序列,hit-testview不再响应。如果为NO,则不发送touchesCancelled:withEvent:消息给hit-testview,这样会使Gesture

Recognizers和hit-test view同时响应触摸序列。

delaysTouchesBegan为NO,表示触摸序列开始时,而手势识别器还未识别出此手势时,touch事件会同时发向hit-testview,这样在手势识别器还未识别出此手势,hit-testview同时也可以收到同样的触摸事件。如果为YES,则在手势识别器在识别手势的过程中,不会有任何触摸事件发送给hit-testview,如果手势识别器最终识别到了手势,则也不会发送任何消息(包括touchesCancelled:withEvent:)给hit-testview;若干手势识别最终没有识别到手势,则所有的触摸事件在发给hit-test

view处理。关于这个特性,可参考UIScrollView的delaysContentTouches属性。这样属性也谨慎使用,使用不当会导致UI无响应。

delaysTouchesEnded,在文档上的解释是,当手势识别器在识别手势时,对于UITouchPhaseEnded阶段的touch会延迟发送给hit-testview,在手势识别成功后,发送给hit-test viewcancel消息,手势识别失败时,发送原来的end消息。其给出了了这样的例子识别双击操作的UITapGestureRecognizer对象,其numberOfTapsRequired设为2,在用户进行双击操作时,如果delaysTouchesEnded为NO,则hit-testview中的调用序列为

touchesBegan:withEvent:,

touchesEnded:withEvent:,

touchesBegan:withEvent:,

and touchesCancelled:withEvent:

如果delaysTouchesEnded为YES,则调用序列为:

touchesBegan:withEvent:,

touchesBegan:withEvent:,

touchesCancelled:withEvent:,

touchesCancelled:withEvent:

但我在实际测试时,并非如此,实际测试的结果是,如果delaysTouchesEnded为NO,则调用序列为:

touchesBegan:withEvent:,

touchesEnded:withEvent:,

TapGestureRecognizer 检测到双击

如果delaysTouchesEnded为YES,则调用序列为:

touchesBegan:withEvent:,

touchesEnded:withEvent:,

TapGestureRecognizer 检测到双击

touchesCancelled:withEvent:

这个问题还没搞清楚!

三.多个Gesture Recognizer之间的关系

在一个view上可以绑定多个GestureRecognizer,在默认情况下,触摸序列中的触摸事件会以不确定的次序在各个gesturerecognizer中传递,直到事件最终发送给hit-test

view(如果中间没被GestureRecognizer识别出并截获的话)。多个GestureRecognizer之间的关系也可以根据需要定制,主要有下面几种行为

1.使其中一个gesturerecognizer失败的情况下,另一个gesture recognizer才能分析事件。

以同时识别单击操作和双击操作为例,两个gesturerecognizers分别用来识别单击和双击,分别为singleTapGesture和doubleTapGesture。在默认情况下,当用户进行单击操作时,singleTapGesture会识别出一个单击操作,doubleTapGesture也会识别出一个双击动作,但我们的意图是,这仅仅是一个双击操作。在这种情况下我们可以使用UIGestureRecognizer的requireGestureRecognizerToFail:方法来使singleTapGesture在doubleTapGesture识别识别的时候才分析事件,如果doubleTapGesture识别出双击事件,则singleTapGesture不会有任何动作。

[singleTapGesture requireGestureRecognizerToFail:doubleTapGesture];

需要注意的是,在这种情况下,如果用户进行单击操作,需要一段延时(即doubleTapGesture识别失败),singleTapGesture才会识别出单击动作,进行单击处理,这段时间很多,对实际使用几乎没有影响。

2.精确控制gesturerecognizer是否响应某个事件或事件序列.

在UIGestureRecognizerDelegate协议中有两个可选方法可以控制gesturerecognizer是否需要识别某些事件

gestureRecognizerShouldBegin:

此方法在gesturerecognizer视图转出UIGestureRecognizerStatePossible状态时调用,如果返回NO,则转换到UIGestureRecognizerStateFailed;如果返回YES,则继续识别触摸序列.(默认情况下为YES)

gestureRecognizer:shouldReceiveTouch:

此方法在window对象在有触摸事件发生时,调用gesturerecognizer的touchesBegan:withEvent:方法之前调用,如果返回NO,则gesturerecognizer不会看到此触摸事件。(默认情况下为YES).

另外,在UIGestureRecognizer类中也有两个可以重写的方法来完成与Delegate方法中相同的功能

- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer*)preventedGestureRecognizer;

- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer*)preventingGestureRecognizer;

3.允许多个手势识别器共同识别

默认情况下,两个gesturerecognizers不会同时识别它们的手势,但是你可以实现UIGestureRecognizerDelegate协议中的

gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:方法对其进行控制。这个方法在这两个gesturerecognizers中的任意一个将block另一个的触摸事件时调用,如果返回YES,则两个gesturerecognizers可同时识别,如果返回NO,则并不保证两个gesturerecognizers必不能同时识别,因为另外一个gesturerecognizer的此方法可能返回YES。也就是说两个gesturerecognizers的delegate方法只要任意一个返回YES,则这两个就可以同时识别;只有两个都返回NO的时候,才是互斥的。默认情况下是返回NO。

有这样一个例子,如果要侦测在window上的所有触摸事件,可以将gesturerecognizer关联到window上,默认情况下如果手势被window识别,则子视图中的gesturerecognizer就失效了,而我们在window上的gesturerecognizer的目的只是监控所有事件,但并不处理这些事件,具体事件的处理还需要子视图中的各个gesturerecognizer去处理,这样我们可以实现window上绑定gesturerecognizer的delegate方法,使gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:返回YES即可。

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {    return YES;}

四.UIScrollView的类似行为

scroll view没有滚动栏,当在scroll view上有触摸行为时其要识别出触摸行为的目的是scrollview本身还是其内容子视图。定制scrollview如何处理这种情况,看查看UIScrollView类的下列属性和方法。

– touchesShouldBegin:withEvent:inContentView:

– touchesShouldCancelInContentView:

canCancelContentTouches

delaysContentTouches

参考:

Event Handling Guide for iOS – Gesture Recognizers

UIGestureRecognizer Class Reference

UIGestureRecognizerDelegate Protocol Reference

Detecting all touches in an app

UIScrollView Class Reference

How to recognize swipe gesture in UIScrollView

UIGestureRecognizer blocks subview for handling touchevents

UIButton touch is delayed when in UIScrollView

Why is scrolling a UITableView much more responsive than scrollinga UIScrollView?

How to cancel touches exactly like UIScrollView?

相关文章

  • GestureRecognizers与触摸事件分发

    一.Gesture Recognizers Gesture Recognizers是在iOS3.2引入的,可以用来...

  • 手势详解

    首先要知道的是 1.这3个属性是作用于GestureRecognizers(手势识别)与触摸事件之间联系的属性。实...

  • 《iOS事件触摸与手势》

    iOS事件触摸与手势 一、事件分发处理【由外到内】在iOS中发生触摸后,事件会加到UIApplication事件队...

  • Android 触摸事件分发

    触摸事件分发 几个重要的方法 触摸事件分发:定义在View中 @Override public boolean d...

  • Android的事件分发

    Android中的事件分为按键事件,触摸事件,轨迹球事件等,其中按键事件是基于焦点分发的,触摸事件是基于位置分发的...

  • 高级UI<第三十三篇>:事件分发机制的简单理解

    在Android开发中,我们经常会处理到屏幕触摸事件,而事件分发机制就是处理屏幕触摸事件的基础。事件分发机制其实很...

  • Android触摸事件-00基础

    事件分发的相关api dispatchTouchEvent:它是传递触摸事件的接口。Activity将触摸事件传递...

  • 应用 Activity 界面 布局层次 分析(4) - 事件分发

    如上图所示,触摸事件分发的流程清晰明了.这里可以看出,触摸事件会先分发到 Activity,然后再ViewGrou...

  • 事件分发基础篇

    1.被分发的对象被分发的对象是那些?被分发的对象是用户触摸屏幕而产生的点击事件,事件主要包括:按下、滑动、抬起与取...

  • 触摸事件之事件分发

    上篇文章中,分析了我之前关于触摸事件的一点疑问,感兴趣的,可点击触摸事件之onTouch和onTouchEvent...

网友评论

      本文标题:GestureRecognizers与触摸事件分发

      本文链接:https://www.haomeiwen.com/subject/hpomzttx.html