hitTest:withEvent:方法(此方法可實現點擊穿透、點擊下層視圖功能)

此方法可實現點擊穿透、點擊下層視圖功能

一. hitTest:withEvent:調用過程

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:方法的處理流程以下:數組

  1. 首先調用當前視圖的pointInside:withEvent:方法判斷觸摸點是否在當前視圖內;
  2. 若返回NO,則hitTest:withEvent:返回nil;
  3. 若返回YES,則向當前視圖的全部子視圖(subviews)發送hitTest:withEvent:消息,全部子視圖的遍歷順序是從top到bottom,即從subviews數組的末尾向前遍歷,直到有子視圖返回非空對象或者所有子視圖遍歷完畢;
  4. 若第一次有子視圖返回非空對象,則hitTest:withEvent:方法返回此對象,處理結束;
  5. 如全部子視圖都返回非,則hitTest:withEvent:方法返回自身(self)。

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:方法

若是父視圖須要對對哪一個子視圖能夠響應觸摸事件作特殊控制,則能夠重寫hitTest:withEvent:pointInside:withEvent:方法。spa

這裏有幾個例子:code


  1. 在 此例子中button,scrollview同爲topView的子視圖,但scrollview覆蓋在button之上,這樣在在button上的觸摸 操做返回的hit-test view爲scrollview,button沒法響應,能夠修改topView的hitTest:withEvent:方法以下: 
    - (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

  2. 網上的一個案例:    對象

      convertPoint:toView:blog

  轉換一個點從接收者座標系到給定的視圖座標系

  - (CGPoint)convertPoint:(CGPoint)point toView:(UIView *)view

  參數

  point

  一個在調用者座標系中的點

  view

  一個包含了須要被轉換的點的視圖。若是視圖是nil,那麼這個方法將會轉換成基於窗口的座標。不然視圖和接收者都要屬於同一個UIWindow對象。

  返回值

  基於視圖的座標系轉換過的點

 

相關文章
相關標籤/搜索