iOS 事件傳遞響應鏈

iOS中加載的時候會先執行main函數ide

int main(int argc, char * argv[]) {
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
    }
}

根據main函數的參數加載UIApplication->AppDelegate->UIWindow->UIViewController->superView->subViews
關係爲:UIApplication.keyWindow.rootViewController.view.subView函數


 

 

那麼,系統是怎麼找到接收觸摸事件發生的視圖的?spa

只經過UIView及其子類查找,調用根視圖的hitTtest:withEvent,其的執行過程以下:3d

iOS使用hit-testing尋找觸摸的view。 Hit-Testing經過檢查觸摸點是否在關聯的view邊界內,若是在,則遞歸地(recursively)檢查該view的全部子view。在層級上處於lowest(我理解就是離用戶最近的view)且邊界範圍包含觸摸點的view成爲hit-test view。肯定hit-test view後,它傳遞觸摸事件給該view。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] == NO) return nil;
    
    // 3.從後往前遍歷本身的子控件
    NSInteger count = self.subviews.count;
    
    for (NSInteger i = count - 1; i >= 0; i--) {
        UIView *childView = self.subviews[i];
        
        // 把當前控件上的座標系轉換成子控件上的座標系
     CGPoint childP = [self convertPoint:point toView:childView];
        
     UIView *fitView = [childView hitTest:childP withEvent:event];
        
        
        if (fitView) { // 尋找到最合適的view
            return fitView;
        }
        
        
    }
    
    // 循環結束,表示沒有比本身更合適的view
    return self;
    
}

 其中,-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)eventblog

這個函數的用處是判斷當前的點擊或者觸摸事件的點是否在當前的view中。繼承

它被hitTest:withEvent:調用,經過對每一個子視圖調用pointInside:withEvent:決定最終哪一個視圖來響應此事件。若是 PointInside:withEvent:返回YES,而後子視圖的繼承樹就會被遍歷(遍歷順序中最早響應的爲:與用戶最接近的那個視圖。 it starts from the top-level subview),即子視圖的子視圖繼續調用遞歸這個函數,直到找到能夠響應的子視圖(這個子視圖的hitTest:withEvent:會返回self,而不是nil);不然,視圖的繼承樹就會被忽略。遞歸

 

 

 

 

相關文章
相關標籤/搜索