iOS系統檢測到手指觸摸(Touch)操做時會將其放入當前活動Application的事件隊列,UIApplication會 從事件隊列中取出觸摸事件並傳遞給key window(當前接收用戶事件的窗口)處理,window對象首先會使用hitTest:withEvent:方法尋找這次Touch操做初始點所在的 視圖(View),即須要將觸摸事件傳遞給其處理的視圖,稱之爲hit-test view。html
window對象會在首先在view hierarchy的頂級view上調用hitTest:withEvent:,此方法會在視圖層級結構中的每一個視圖上調用pointInside:withEvent:,若是pointInside:withEvent:返回YES,則繼續逐級調用,直到找到touch操做發生的位置,這個視圖也就是hit-test view。ios
hitTest:withEvent:方法的處理流程以下:數組
hitTest:withEvent:方法忽略隱藏(hidden=YES)的視圖,禁止用戶操做(userInteractionEnabled=YES)的視圖,以及alpha級別小於0.01(alpha<0.01)的視圖。若是一個子視圖的區域超過父視圖的bound區域(父視圖的clipsToBounds 屬 性爲NO,這樣超過父視圖bound區域的子視圖內容也會顯示),那麼正常狀況下對子視圖在父視圖以外區域的觸摸操做不會被識別,由於父視圖的 pointInside:withEvent:方法會返回NO,這樣就不會繼續向下遍歷子視圖了。固然,也能夠重寫 pointInside:withEvent:方法來處理這種狀況。app
對於每一個觸摸操做都會有一個UITouch對 象,UITouch對象用來表示一個觸摸操做,即一個手指在屏幕上按下、移動、離開的整個過程。UITouch對象在觸摸操做的過程當中在不斷變化,因此在 使用UITouch對象時,不能直接retain,而須要使用其餘手段存儲UITouch的內部信息。UITouch對象有一個view屬性,表示此觸摸操做初始發生所在的視圖,即上面檢測到的hit-test view,此屬性在UITouch的生命週期再也不改變,即便觸摸操做後續移動到其餘視圖之上。ide
若是父視圖須要對對哪一個子視圖能夠響應觸摸事件作特殊控制,則能夠重寫hitTest:withEvent:或pointInside:withEvent:方法。spa
這裏有幾個例子:code
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event { UIView *result = [super hitTest:point withEvent:event]; CGPoint buttonPoint = [underButton convertPoint:point fromView:self]; if ([underButton pointInside:buttonPoint withEvent:event]) { return underButton; } return result; }
這樣若是觸摸點在button的範圍內,返回hittestView爲button,從button按鈕能夠響應點擊事件。htm
網上的一個案例: 對象
convertPoint:toView:blog
轉換一個點從接收者座標系到給定的視圖座標系
- (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view
參數
point
一個在調用者座標系中的點
view
一個包含了須要被轉換的點的視圖。若是視圖是nil,那麼這個方法將會轉換成基於窗口的座標。不然視圖和接收者都要屬於同一個UIWindow對象。
返回值
基於視圖的座標系轉換過的點