1. 程式人生 > >iOS事件傳遞機制詳解

iOS事件傳遞機制詳解

概述


  1. 當用戶觸控實際螢幕時,會生成一個Touch Event,將此事件新增到UIApplication管理的事件佇列之中。
  2. UIApplication從事件佇列之中按順序取出事件分發到檢視去處理。
  3. 當事件被髮出以後,會從keyWindow開始,依次向上傳遞,包括Controller以及View,最後找到合適的檢視來響應事件。

事件傳遞順序


涉及到兩個方法:
- (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event;(以下簡稱hitTest)


- (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event; (以下簡稱pointInside)
當UIApplication傳送事件到keyWindow時,會呼叫 hitTest來尋找最合適的檢視處理事件。判斷邏輯如下:

  1. 首先判斷自身是否能夠響應觸控事件(userInteractionEnabled==NO、hidden==YES、alpha<=0.01不能響應觸控事件),則hitTest返回nil。
  2. 如果可以響應觸控事件,呼叫pointInside來判斷是否在顯示區域內,如果不在其中,pointInside
    返回NO,同時hitTest返回nil。
  3. 如果 pointInside返回YES,表示在當前的檢視之中,然後倒序(劃重點)遍歷該檢視的子檢視,重複上述步驟,知道某一檢視可以響應,hitTest:返回該檢視。
  4. 如果執行完上述步驟以後,沒有符合條件的檢視響應事件,則返回檢視本身,表示只有當前檢視符合條件,能夠處理該事件。

Talk is cheap, show me the code.


- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {

    //步驟1
    if (self.userInteractionEnabled
== NO || self.hidden == YES || self.alpha <= 0.01) { return nil; } //步驟2 if (![self pointInside:point withEvent:event]) { return nil; } //步驟3 NSInteger subViewCount = self.subviews.count; for (NSInteger i = subViewCount - 1; i >= 0; i--) { UIView *subView = self.subviews[i]; CGPoint childPoint = [self convertPoint:point toView:subView]; UIView *hitView = [subView hitTest:childPoint withEvent:event]; if (hitView) { return hitView; } } //步驟4 return self; }