delaysTouchesEnded,在文檔上的解釋是,當手勢辨識器在識別手勢時,對於UITouchPhaseEnded階段的touch會延遲發送給hit-test view,在手勢識別成功後,發送給hit-test view cancel訊息,手勢識別失敗時,發送原來的end訊息。其給出了了這樣的例子識別雙擊操作的UITapGestureRecognizer對象,其numberOfTapsRequired設為2,在使用者進行雙擊操作時,如果delaysTouchesEnded為NO,則hit-test view中的調用序列為
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上可以綁定多個Gesture Recognizer,在預設情況下,觸摸序列中的觸摸事件會以不確定的次序在各個gesture recognizer中傳遞,直到事件最終發送給hit-test view(如果中間沒被Gesture Recognizer識別出並截獲的話)。多個Gesture Recognizer之間的關係也可以根據需要定製,主要有下面幾種行為
1.使其中一個gesture recognizer失敗的情況下,另一個gesture recognizer才能分析事件。以同時識別單擊操作和雙擊操作為例,兩個gesture recognizers分別用來識別單擊和雙擊,分別為singleTapGesture和doubleTapGesture。在預設情況下,當使用者進行單擊操作時,singleTapGesture會識別出一個單擊操作,doubleTapGesture也會識別出一個雙擊動作,但我們的意圖是,這僅僅是一個雙擊操作。在這種情況下我們可以使用UIGestureRecognizer的requireGestureRecognizerToFail:方法來使singleTapGesture在doubleTapGesture識別識別的時候才分析事件,如果doubleTapGesture識別出雙擊事件,則singleTapGesture不會有任何動作。
[singleTapGesture requireGestureRecognizerToFail:doubleTapGesture];
需要注意的是,在這種情況下,如果使用者進行單擊操作,需要一段延時(即doubleTapGesture識別失敗),singleTapGesture才會識別出單擊動作,進行單擊處理,這段時間很多,對實際使用幾乎沒有影響。
2.精確控制gesture recognizer是否響應某個事件或事件序列.
在UIGestureRecognizerDelegate協議中有兩個可選方法可以控制gesture recognizer是否需要識別某些事件
- gestureRecognizerShouldBegin:
此方法在gesture recognizer視圖轉出UIGestureRecognizerStatePossible狀態時調用,如果返回NO,則轉換到UIGestureRecognizerStateFailed;如果返回YES,則繼續識別觸摸序列.(預設情況下為YES)
- gestureRecognizer:shouldReceiveTouch:
此方法在window對象在有觸摸事件發生時,調用gesture recognizer的touchesBegan:withEvent:方法之前調用,如果返回NO,則gesture recognizer不會看到此觸摸事件。(預設情況下為YES).
另外,在UIGestureRecognizer類中也有兩個可以重寫的方法來完成與Delegate方法中相同的功能
- (BOOL)canPreventGestureRecognizer:(UIGestureRecognizer *)preventedGestureRecognizer;
- (BOOL)canBePreventedByGestureRecognizer:(UIGestureRecognizer *)preventingGestureRecognizer;
3.允許多個手勢辨識器共同識別預設情況下,兩個gesture recognizers不會同時識別它們的手勢,但是你可以實現UIGestureRecognizerDelegate協議中的
gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:方法對其進行控制。這個方法在這兩個gesture recognizers中的任意一個將block另一個的觸摸事件時調用,如果返回YES,則兩個gesture recognizers可同時識別,如果返回NO,則並不保證兩個gesture recognizers必不能同時識別,因為另外一個gesture recognizer的此方法可能返回YES。也就是說兩個gesture recognizers的delegate方法只要任意一個返回YES,則這兩個就可以同時識別;只有兩個都返回NO的時候,才是互斥的。預設情況下是返回NO。
有這樣一個例子,如果要偵測在window上的所有觸摸事件,可以將gesture recognizer關聯到window上,預設情況下如果手勢被window識別,則子視圖中的gesture recognizer就失效了,而我們在window上的gesture recognizer的目的只是監控所有事件,但並不處理這些事件,具體事件的處理還需要子視圖中的各個gesture recognizer去處理,這樣我們可以實現window上綁定gesture recognizer的delegate方法,使gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:返回YES即可。
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer { return YES;}
四.UIScrollView的類似行為scroll view沒有滾動欄,當在scroll view上有觸摸行為時其要識別出觸摸行為的目的是scroll view本身還是其內容子視圖。定製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 touch events
UIButton touch is delayed when in UIScrollView
Why is scrolling a UITableView much more responsive than scrolling a UIScrollView?
How to cancel touches exactly like UIScrollView?