Gesture Recognizers與觸摸事件分發[轉]

來源:互聯網
上載者:User

標籤:

一.Gesture Recognizers

Gesture Recognizers是在iOS3.2引入的,可以用來識別手勢、簡化定製視圖事件處理的對象。Gesture Recognizers的基類為UIGestureRecognizer,這一個抽象基類,定義了實現底層手勢識別行為的編程介面。在UIKit架構中提供了6個具體的手勢識別類,用來識別常見的手勢。這6個手勢辨識器類為:

  • UITapGestureRecognizer:用來識別點選手勢,包括單擊,雙擊,甚至三擊等。
  • UIPinchGestureRecognizer:用來識別手指捏合手勢。
  • UIPanGestureRecognizer:用來識別拖動手勢。
  • UISwipeGestureRecognizer:用來識別Swipe手勢。
  • UIRotationGestureRecognizer:用來識別旋轉手勢。
  • UILongPressGestureRecognizer:用來識別長按手勢。

為了識別手勢,需要將Gesture Recognizers關聯到其檢測觸摸事件的view上,可以使用UIView的addGestureRecognizer:方法將手勢辨識器綁定到視圖上。Gesture Recognizers在觸摸事件處理流程中,處於觀察者的角色,其不是view層級結構的一部分,所以也不參與responder chain。在將觸摸事件發送給hit-test view之前,系統會先將觸摸事件發送到hit-test view上綁定的或hit-test view父視圖(superview)上綁定的Gesture Recognizers上。其流程大概如所示:

注:圖中view與Gesture Recognizer的關係是,Gesture Recognizer關聯在view或view的superview(可能多級)上。

二.Gesture Recognizers與事件分發路徑的關係

Gesture Recognizers可能會延遲將觸摸事件發送到hit-test view上,預設情況下,當Gesture Recognizers識別到手勢後,會向hit-test view發送cancel訊息,來取消之前發給hit-test view的事件。控制這個流程的是UIGestureRecognizer的三個屬性

    • cancelsTouchesInView (預設為YES)
    • delaysTouchesBegan (預設為NO)
    • delaysTouchesEnded (預設為YES)
    • cancelsTouchesInView為YES,表示當Gesture Recognizers識別到手勢後,會向hit-test view發送 touchesCancelled:withEvent:訊息來取消hit-test view對此觸摸序列的處理,這樣只有Gesture Recognizers能響應此觸摸序列,hit-test view不再響應。如果為NO,則不發送touchesCancelled:withEvent:訊息給hit-test view,這樣會使Gesture Recognizers和hit-test view同時響應觸摸序列。

    • delaysTouchesBegan為NO,表示觸摸序列開始時,而手勢辨識器還未識別出此手勢時,touch事件會同時發向hit-test view,這樣在手勢辨識器還未識別出此手勢,hit-test view同時也可以收到同樣的觸摸事件。如果為YES,則在手勢辨識器在識別手勢的過程中,不會有任何觸摸事件發送給hit-test view,如果手勢辨識器最終識別到了手勢,則也不會發送任何訊息(包括touchesCancelled:withEvent:)給hit-test view;若干手勢識別最終沒有識別到手勢,則所有的觸摸事件在發給hit-test view處理。關於這個特性,可參考UIScrollView的delaysContentTouches屬性。這樣屬性也謹慎使用,使用不當會導致UI無響應。

    • 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?

Gesture Recognizers與觸摸事件分發[轉]

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.