一、響應者鏈
- 首先判斷主窗口(keyWindow)自己是否能接受觸摸事件
- 判斷觸摸點是否在自己身上
- 子控件數組中從后往前遍歷子控件,重復前面的兩個步驟(所謂從后往前遍歷子控件,就是首先查找子控件數組中最后一個元素,然后執行1、2步驟)
- view,比如叫做fitView,那么會把這個事件交給這個fitView,再遍歷這個fitView的子控件,直至沒有更合適的view為止。
-
如果沒有符合條件的子控件,那么就認為自己最合適處理這個事件,也就是自己是最合適的view
響應鏈
二、事件傳遞
- 如果當前view是控制器的view,那么控制器就是上一個響應者,事件就傳遞給控制器;如果當前view不是控制器的view,那么父視圖就是當前view的上一個響應者,事件就傳遞給它的父視圖
- 在視圖層次結構的最頂級視圖,如果也不能處理收到的事件或消息,則其將事件或消息傳遞給window對象進行處理
- 如果window對象也不處理,則其將事件或消息傳遞給UIApplication對象
- 如果UIApplication也不能處理該事件或消息,則將其丟棄
三、處理過程
在自定義UIView為基類的控件時,我們可以重寫這幾個方法來進行點擊回調。在回調中,我們可以看到方法接收兩個參數,一個UITouch對象的集合,還有一個UIEvent對象。這兩個參數分別代表的是點擊對象和事件對象。
- 事件對象
iOS使用UIEvent表示用戶交互的事件對象,在UIEvent.h文件中,我們可以看到有一個UIEventType類型的屬性,這個屬性表示了當前的響應事件類型。分別有多點觸控、搖一搖以及遠程操作(在iOS之后新增了3DTouch事件類型)。在一個用戶點擊事件處理過程中,UIEvent對象是唯一的 - 點擊對象
UITouch表示單個點擊,其類文件中存在枚舉類型UITouchPhase的屬性,用來表示當前點擊的狀態。這些狀態包括點擊開始、移動、停止不動、結束和取消五個狀態。每次點擊發生的時候,點擊對象都放在一個集合中傳入UIResponder的回調方法中,我們通過集合中對象獲取用戶點擊的位置。其中通過- (CGPoint)locationInView:(nullable UIView *)view獲取當前點擊坐標點,- (CGPoint)previousLocationInView:(nullable UIView *)view獲取上個點擊位置的坐標點。
響應鏈的應用
通過重寫查找事件處理者的方法來實現不規則形狀點擊。
最常見的不規則視圖就是圓形視圖
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
const CGFloat halfWidth = 100;
CGFloat xOffset = point.x - 100;
CGFloat yOffset = point.y - 100;
CGFloat radius = sqrt(xOffset * xOffset + yOffset * yOffset);
return radius <= halfWidth;
}