標籤:
iOS中載入的時候會先執行main函數
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
那麼,系統是怎麼找到接收觸摸事件發生的視圖的?
只通過UIView及其子類尋找,調用根視圖的hitTtest:withEvent,其的執行過程如下:
iOS使用hit-testing尋找觸摸的view。 Hit-Testing通過檢查觸摸點是否在關聯的view邊界內,如果在,則遞迴地(recursively)檢查該view的所有子view。在層級上處於lowest(我理解就是離使用者最近的view)且邊界範圍包含觸摸點的view成為hit-test view。確定hit-test view後,它傳遞觸摸事件給該view。
- (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 *)event
這個函數的用處是判斷當前的點擊或者觸摸事件的點是否在當前的view中。
它被hitTest:withEvent:調用,通過對每個子視圖調用pointInside:withEvent:決定最終哪個視圖來響應此事件。如果 PointInside:withEvent:返回YES,然後子視圖的繼承樹就會被遍曆(遍曆順序中最先響應的為:與使用者最接近的那個視圖。 it starts from the top-level subview),即子視圖的子視圖繼續調用遞迴這個函數,直到找到可以響應的子視圖(這個子視圖的hitTest:withEvent:會返回self,而不是nil);否則,視圖的繼承樹就會被忽略。
iOS 事件傳遞響應鏈