1. 響應(yīng)者鏈
用戶觸摸屏幕后钞瀑,手機硬件受到觸摸事件,分發(fā)給UIApplication,之后逐步傳遞到UIWindow->UIView->subViews(該數(shù)組從后向前遍歷,即用戶看到屏幕最上層的視圖却特,這就解釋了為什么用戶點擊事件能及時響應(yīng)了)。
// point是該視圖的坐標系上的點
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
// 1.判斷自己能否接收觸摸事件
if (self.userInteractionEnabled == NO || self.hidden == YES || self.alpha <= 0.01) return nil;
// 2.判斷觸摸點在不在自己范圍內(nèi)
if (![self pointInside:point withEvent:event]) return nil;
// 3.從后往前遍歷自己的子控件筛圆,看是否有子控件更適合響應(yīng)此事件
int count = self.subviews.count;
for (int i = count - 1; i >= 0; i--) {
UIView *childView = self.subviews[i];
CGPoint childPoint = [self convertPoint:point toView:childView];
UIView *fitView = [childView hitTest:childPoint withEvent:event];
if (fitView) {
return fitView;
}
}
// 沒有找到比自己更合適的view
return self;
}
hitTest方法會首先判斷觸摸點是否在self視圖(當前視圖)裂明,如果不在,直接返回nil顽染,則self及其所有的子視圖都被忽略處理該事件漾岳,此為第一層判斷(1)轰绵;如果當前點在self視圖粉寞,則遍歷subviews數(shù)組,如果數(shù)組中有view能夠響應(yīng)該觸摸事件左腔,則返回該子view(fitView)唧垦,此為第二層判斷(2);如果self的所有子視圖都不能響應(yīng)觸摸事件液样,則返回self振亮,由self視圖處理觸摸事件,此為第三層判斷(3)鞭莽。
第一層于第三層都好理解坊秸,但是第二層使用了遞歸去尋找最合適的子View,有點繞澎怒。著重分析下第二層褒搔,遍歷subviews數(shù)組時,遍歷的每個元素(從后向前,最后加入的view)執(zhí)行hitTest時星瘾,又會從第一層開始走孽,如果返回nil,那么就從該元素的兄弟視圖開始執(zhí)行hitTest琳状,如果找到了合適的兄弟視圖能夠響應(yīng)hitTest磕瓷,則直接返回,所有的遞歸操作結(jié)束念逞,返回值會一直回傳到最開始分發(fā)事件的hitTest困食;如果沒有找到則轉(zhuǎn)入第三層,返回self翎承。