? ? ? 當你手指觸摸屏幕后會發(fā)生以下事情:觸摸事件被封裝成一個UIEvent事件,去當前iOS操作系統(tǒng)的active app隊列中取當前活躍的APP矢腻,把event傳給它--->event傳給UIApplication--->傳給UIWindow的rootViewController(rootVC)--->調(diào)用rootVC.view的所有subviews的hitTest:event:方法。哪個view的hitTest:event方法返回非nil值爱态,則觸摸事件就交給該view處理衬潦。
? ? ? ?當設(shè)計一個app的時候,想動態(tài)的去響應(yīng)一個事件隆圆。例如漱挚,在屏幕上的一個觸摸事件可能在不同的對象中都發(fā)生,并且你不得不決定由哪一個對象來響應(yīng)這個事件并且嘗試去理解怎么樣的一個對象接收了到這個事件渺氧。
? ? ? ?當一個常見的用戶事件發(fā)生的時候旨涝,UIKit會創(chuàng)建一個事件對象Event Object,該對象包含了事件處理所必須得一些信息。然后它會將事件對象置于激活的app事件隊列侣背。例如觸摸事件白华,該觸摸時事件對象是一系列觸摸信息包裝集。例如手勢事件贩耐,該事件是一個動態(tài)的變量它取決于你使用了什么框架以及你感興趣的手勢事件類型弧腥。
? ? ? ? 一個事件會游走于指定的傳遞路徑很長的時間直到它被處理。首先潮太,這個單例 UIApplication 對象會從事件隊列頂部拿出一個事件對象用于分發(fā)處理管搪。比較典型的就是,它會發(fā)送這個事件給 Window 對象铡买,Wiindow對象會遞交事件給原始對象 initial object去處理更鲁。initial object取決于事件的類型。
? ? ? ?觸摸事件:對于觸摸事件奇钞,window對象會嘗試著首先將事件傳遞給觸摸事件發(fā)生點得View岁经。這個View被視為“命中測試view” (hit-test view)。尋找“命中測試view”的過程被稱作“命中測試”,關(guān)于“命中測試”會在下面的命中測試返回觸摸事件發(fā)生點的view有詳情描述蛇券。
? ? ? ?手勢和遠程控制事件:對于這些事件缀壤,window對象發(fā)送震動手勢或者遠程控制事件給第一響應(yīng)者去處理,關(guān)于第一響應(yīng)者的定義在下面的響應(yīng)者鏈的構(gòu)造中有詳情描述纠亚。
?? ? ? 最終所有的事件響應(yīng)路徑都是為了去尋找那個能夠響應(yīng)并處理該事件的對象塘慕。因此,UIkit會首先發(fā)送該事件給最適合處理該事件的對象蒂胞。對于觸摸事件图呢,這個最適合處理的對象就是 hit-test view既“命中測試view”,并且對于其它事件,這個對象就是“第一響應(yīng)者”。下面的幾個部分將詳細的解釋更多的關(guān)于“命中測試view”和第一響應(yīng)者的選擇蛤织。
? ? ? ?命中測試返回觸摸事件發(fā)生點的view
? ? ? ?iOS使用“命中測試”(hit-testing)去尋找觸摸發(fā)生下的view赴叹。命中測試會執(zhí)行檢測判斷是否改觸摸點發(fā)生在某個具體的view的相對邊界之內(nèi)。如果檢測是的指蚜,它就會遞歸的去檢測該view的所有子view乞巧。該view的層級最底端view包含觸摸點,它就成為了“命中測試view”摊鸡。之后iOS就會決定誰是命中測試view,并且遞交觸摸事件給它處理绽媒。
? ? ? ? 為了去闡明這個過程,假設(shè)用戶觸摸 view E如圖免猾。iOS會以這樣的順序去尋找命中測試view通過檢測所有的子view.
? ? ? ? 方法hitTest:withEvent傳入CGPoint和UIEvent返回命中測試view是辕。這個方法hitTest:withEvent開始執(zhí)行通過調(diào)用自身的ponitInside:withEvent方法。如果傳入hitTest:withEvent的point在view的邊界之內(nèi)猎提。ponitInside:withEvent方法就會返回YES获三。然后該方法會遞歸調(diào)用hitTest:withEvent方法在每一個返回YES的子view上。
? ? ? ? 如果傳入的hitTest:withEvent的點不在view的邊界之內(nèi)锨苏,首先會調(diào)用ponitInside:withEvent方法返回NO,該point會被忽略石窑,并且hitTest:withEvent返回nil,如果一個子view返回NO蚓炬,那么整個view層級的分支都會被忽略松逊,因為如果觸摸點沒有發(fā)生在子view,她也不可能發(fā)生在任何子view的子view肯夏。這就意味著任何子view上面的點都在邊界之外并且它的父view也不能接受觸摸事件经宏,因為觸摸點必須同時在父view和子view的邊界之內(nèi)。這種情況可能會發(fā)生驯击,如果子view的clipsToBound屬性設(shè)為NO烁兰。
? ? ? ? 注意:一個觸摸事件對象將會被關(guān)聯(lián)于命中測試view的整個生命周期,即使這個觸摸后來移到了view的邊界之外徊都。
? ? ? ? 命中測試view被賦予了第一個處理觸摸事件的機會沪斟,如果命中測試view不能處理該事件,該事件就會交付給view響應(yīng)者鏈的上一級處理直到系統(tǒng)找到一個能夠處理該事件的對象暇矫。