前置阅读:
1. iOS私有API(二) UIGestureRecognizerDelegate的两个函数
2. iOS私有API(三) UIWebView下的手势识别器gestureRecognizer
UIWebView下有很多的手势,它是怎么管理的呢?主要是两种途径:自管理和委托,即
1. 继承自UIGestureRecognizer或其子类,重载以下两个函数
// same behavior as the equivalent delegate methods, but can be used by subclasses to define class-wide prevention rules // for example, a UITapGestureRecognizer never prevents another UITapGestureRecognizer with a higher tap count - (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer; - (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer;
2. 通过UIGestureRecognizerDelegate,当中还有non-public API。
这里只讨论由UIWebBrowserView和UIWebDocumentView管理的手势。其它assistant所管理的手势,他们的手势的delegate都是各自的assistant,不需要UIWebBrowserView去操心。不过这些assistant和UIWebBrowserView之间都是互相引用的关系,即assistant有成员变量保存UIWebBrowserView的实例指针,究竟assistant在处理手势时让UIWebBrowserView帮了什么忙,这个有空再研究了。
UIWebBrowserView只管理一个手势UIWebTouchEventsGestureRecognizer。这个手势很强势,重载了 canBePreventedByGestureRecognizer 函数,永远返回NO,即不会被任何手势阻止。实际上,TouchEvents手势在其state未变成began之前,就会调用一下delegate(UIWebBrowserView)的action,此时UIWebBrowserView查询到UIWebTouchEventsGestureRecognizer仍是possible state,会做一些清理上次操作的工作。在这个预处理之前,TouchEvents手势已经向内核WebCore查询过是否有js的preventDefault要求了,并把这个信息作为成员变量保存着,故这次的预处理如果发现preventDefault=true,还会做些额外的操作。
UIWebDocumentView是UIWebBrowserView的父类,管理6个手势
UITapGestureRecognizer *_singleTapGestureRecognizer; UITapGestureRecognizer *_doubleTapGestureRecognizer; UITapGestureRecognizer *_twoFingerDoubleTapGestureRecognizer; UILongPressGestureRecognizer *_highlightLongPressGestureRecognizer; UILongPressGestureRecognizer *_longPressGestureRecognizer; UIPanGestureRecognizer *_twoFingerPanGestureRecognizer;
而且UIGestureRecognizerDelegate这个protocol是由UIWebDocumentView实现的,确切来说,是由UIWebDocumentView(Interaction)这个category来做的。
我们来看看UIWebDocumentView如何实现UIGestureRecognizerDelegate。
1. - (BOOL)_gestureRecognizer:(id)arg1 shouldReceiveTouch:(id)arg2;
如果arg1为两个doubleTap之一时,返回YES,即双击操作始终接收touch;如果是其它手势,再检测一下这个touch是否点在了插件view上(插件包括:音视频、MapKitView、iAd),如果是,则不接收这个touch。
2. - (BOOL)_gestureRecognizer:(id)arg1 canPreventGestureRecognizer:(id)arg2;
BOOL result = YES; if (m_highlightRecognizer == gestureRecognizer || m_longPressRecognizer == gestureRecognizer) { Class cls = [UIScrollViewPanGestureRecognizer class]; result = [otherGestureRecognizer isKindOfClass:cls] == NO; } return result;
3. - (BOOL)_gestureRecognizer:(id)arg1 canBePreventedByGestureRecognizer:(id)arg2;
有两种情况返回YES:
情况1:如果arg2不是UITextInteractionAssistant.loupeGesture && arg2不是UIWebSelectionAssistant所管理的1.5次点击手势或长按手势
情况2:arg1不是UIWebDocumentView管理的两个longPress手势
4. - (BOOL)_gestureRecognizer:(id)arg1 shouldRecognizeSimultaneouslyWithGestureRecognizer:(id)arg2;
BOOL result = NO; if ((arg1 == m_highlightRecognizer && arg2 == m_longPressRecognizer) || (arg2 == m_highlightRecognizer && arg1 == m_longPressRecognizer) || (_singleTaparg1 == arg1 && _textSelectionAssistant.singleTapGesture == arg2) || (_textSelectionAssistant.singleTapGesture == arg1 && _singleTaparg1 == arg2)) { result = YES; } return result;
5. - (BOOL)_gestureRecognizerShouldBegin:(id)arg1;
这个的实现最复杂,需要根据当前touch的位置做各种判断,会使用线程锁进入内核WebCore做查询。进入这个回调时,手势已经接收到足够的touch信息,所以在此回调中去询问手势识别器实例的各个状态时,除了state外都已是对的了。因比较复杂,在别的文章里再说吧。