iOS中Touches,Presses,and Gestures 文檔總結(jié)

最近把這個小系列的文檔刷了一遍,結(jié)合另外一篇 Understanding Event Handling, Responders, and the Responder Chain,對 iOS 中事件的傳遞和處理有了比較全面的理解。

核心類

  • UIResponder
  • UIEvent
  • UITouch
  • UIPress
  • UIGestureRecognizer

其中 UIResponder 和 UIEvent 是事件傳遞過程用到的類,UITouch,UIPress 和 UIGestureRecognizer 是事件處理過程用到的類。

UIKit 在收到各種事件后封裝成 UIEvent 并通過 UIResponder 進行傳遞。

響應(yīng)鏈與事件傳遞

蘋果在事件傳遞中采用了一個單向鏈表的響應(yīng)鏈設(shè)計,即事件在鏈表中向后傳遞,直到找到一個能響應(yīng)該事件的響應(yīng)者。事件即 UIEvent,響應(yīng)者即 UIResponder。UIResponder 的 nextResponder 即是鏈表指向下一個響應(yīng)者的指針。

響應(yīng)鏈的起始節(jié)點就是 firstResponder,各種事件尋找 firstResponder 的方法不同。

Touch events
The first responder is the view in which the touch occurred.

Press events
The first responder is the responder that has focus.

Shake-motion events
The first responder is the object that you (or UIKit) designate as the first responder.

Remote-control events
The first responder is the object that you (or UIKit) designate as the first responder.

Editing menu messages
The first responder is the object that you (or UIKit) designate as the first responder.

Touch 事件是用戶在屏幕上點擊觸發(fā)的事件,這是最多的一類事件,蘋果提供的處理和追蹤方法也最豐富。

Press 事件是外接設(shè)備的物理按鍵產(chǎn)生的事件,比如蘋果外接的游戲手柄,它的很多處理方法都和 Touch 事件一致,是在 iOS 9 中增加的特性,不做游戲開發(fā)基本也用不上。

Touch 事件是如何尋找 firstResponder 的?

蘋果通過 hitTest 方法和 pointInside 方法在視圖樹中從上到下一層一層測試到底點擊事件應(yīng)該由哪個響應(yīng)者響應(yīng)。找到的這個響應(yīng)者就是 touch 事件的 firstResponder。

事件處理

UIKit 將用戶點擊封裝成 UITouch,然后裝載到 UIEvent 中通過 touches 系列方法回調(diào)給 UIResponder:

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;

我們可以覆蓋這幾個方法來處理 touch 事件,UIView 是繼承自 UIResponder 的,所以我們常用的 UI 組件都包含這幾個方法。

UIEvent

這個類的主要作用是裝載 UITouch 對象,并提供一些查詢和追蹤方法。

UITouch

這個類包含了用戶點擊的各種信息,包括位置、次數(shù)、時間、力度、角度等。

Gesture

蘋果提供的 UIGestureRecognizer 是一組強大的設(shè)計,提供了很多功能,讓我們能將用戶的動作按特征抽象成一個手勢,實現(xiàn)了手勢的識別和處理的解耦。

Gesture 中也有 touches 系列方法,使用方法和 UIResponder 類似。我們可以在這里追蹤 touch 的特征并解讀成各種手勢。我們可以使用自定義的 Gesture 來替代 UIResponder 的 touch 識別邏輯,封裝性和復(fù)用性更好。

Gesture 和響應(yīng)鏈的關(guān)系

Gesture 是被添加到 view 上的,它不參與響應(yīng)鏈的傳遞,但是它會先于 view 對事件進行響應(yīng)。它還提供了一組方法來控制 touch 是否被傳遞給相應(yīng)的 view。

自定義 Gesture

自定義 Gesture 十分強大,我們需要注意 Gesture 有兩種類型:離散手勢和連續(xù)手勢。不同的類型在識別過程中對 Gesture 狀態(tài)的改變路徑是不同的。

實現(xiàn)自定義 Gesture 需要做三件事:

  • 在 touches 系列方法中解析用戶動作特征
  • 根據(jù)解析結(jié)果設(shè)置相應(yīng)的狀態(tài)
  • 清理狀態(tài)和數(shù)據(jù)值

多個手勢的疊加

蘋果提供了許多方法來幫助我們處理多個手勢同時存在的情況:

  • 多個手勢同時分別進行識別
  • 一個手勢要在另一個手勢識別失敗之后才開始識別

實話說蘋果在此處提供的方法有些凌亂,UIGestureRecognizerDelegate 和 UIGestureRecognizer 中存在許多相同作用的方法。我猜想大概是為了方便我們使用,在使用系統(tǒng)定義的 Gesture 時可以使用 delegate,在自定義的 Gesture 時可以覆蓋 UIGestureRecognizer 中的方法。

更高精度的 touch 追蹤

UIKit 處理 touch 事件的頻率是 60Hz,蘋果在 iOS 9 之后的版本中添加了一些特性讓我們可以獲取更高精度的 touch,主要是因為出現(xiàn)了采樣頻率更高的設(shè)備,比如 Apple Pencil。

touch 預(yù)測

蘋果在 iOS 9 中還做了一些優(yōu)化來減少追蹤 touch 時的卡頓,UIEvent 中提供了對之后 touch 事件的預(yù)測,具體的可以看文檔。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容