今天講一下hitTest這個方法。
我們先看一張圖:
流程圖
當用戶點擊屏幕后,UIApplication先響應事件,然后傳遞給UIWindow。如果UIWindow可以響應,就開始遍歷window的subviews。遍歷的過程中,如果第一個view1可以響應,那就遍歷view1的子視圖(subviews)。如果view1不響應,就繼續往下找view2,以此類推。
我們來看兩個方法:
為了方便,我們將兩個方法簡稱為A和B
方法A: - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;
方法B: - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;
對View進行重寫這個兩個方法后,就會發現點擊屏幕后,首先響應的是方法A。
如果方法A中,我們沒有調用父類的這個方法,那就根據這個方法A的返回view,作為響應事件的view。(當然返回nil,就是這個view不響應)
如果方法A中,我們調用了父類的這個方法,也就是:[super hitTest:point withEvent:event];
,這個時候系統就要調用方法B;通過這個方法的返回值,來判斷當前這個view能不能響應消息。
如果方法B返回的是NO,那就不用再去遍歷它的子視圖。方法A返回的view就是可以響應事件的view。
如果方法B返回的是YES,那就去遍歷它的子視圖。(就是上圖我們描述的那樣,找到合適的view返回,如果找不到,那就由方法A返回的view去響應這個事件。)
因此總結下來:
// 返回一個view來響應事件 (我們如果不想影響系統的事件傳遞鏈,在這個方法內,最好調用父類的這個方法)
- (nullableUIView *)hitTest:(CGPoint)point withEvent:(nullableUIEvent *)event;
// 返回的值可以用來判斷是否繼續遍歷子視圖(返回的根據是觸摸的point是否在view的frame范圍內)
- (BOOL)pointInside:(CGPoint)point withEvent:(nullableUIEvent *)event;