iOS基礎06——事件響應鍊
移動應用的最大特性就是響應使用者互動操作,那麼iOS系統是如何去響應一個簡單的點選事件的呢?系統如何精準地定位一個事件的響應者呢?
首先一個事件産生後,系統會将其包裝成一個uievent和uitouch對象,然後傳給目前的app!目前app一級一級查找響應者的規程就形成了一個事件響應鍊!
事件傳遞進來時,uiapplication會将事件放置到隊列中,然後會從隊列中取出事件傳遞給keywindow!注意每一個view都含有以下兩個方法:
1、擷取到響應事件的view,然後傳遞回去;
[hittest:withevent:]
2、判斷事件是否在目前view的範圍裡!
[pointinside:withevent:]
具體的實作如下圖
widow會先檢視點選事件是否在自己的範圍内,如果是,就會繼續查詢子視圖!如圖所示,如果目前視圖滿足要求就會繼續查找目前視圖的子視圖,否則會查找同等級的兄弟視圖,依次類推,直到查到為止。
舉個例子:
如果在viewTwo的非viewThree區域進行一個點選事件,則會在viewOne的pointInside方法中得到true,然後hit test就會繼續周遊子視圖,viewTwo的pointInside方法也傳回true,是以還會繼續周遊子視圖,到了viewthree,pointinside方法傳回false,是以最終的hit test就截止到viewTwo,于是将viewTwo傳回去,viewTwo就是最終的響應者了!
其次有個情況就是子視圖超過父視圖的範圍内的點選事件!如圖,在viewthree的非viewtwo的重疊區域進行點選事件,則響應鍊在到viewtwo的pointinside那就被截斷了,view two的hit test會傳回nil,也就是說找不到響應者,事件不會被響應!
那麼這種情況怎麼才能讓其進行響應呢?這個時候必須得重寫hit test的實作才可以讓事件傳遞下去:
-(UIView )hitTest:(CGPoint)point withEvent:(UIEvent)event
{
UIView *view = [super hitTest:point withEvent:event];
if (view == nil) {
for (UIView *subView in self.subviews) {
CGPoint myPoint = [subViewconvertPoint:point fromView:self];
if (CGRectContainsPoint(subView.bounds, myPoint)) {
return subView;
}
}
}
return view;
}
另外不響應事件還可能
- 是view被隐藏了hide,
- view不響應了userinteractionenable=no;
- 透明度alpha<0.1
面試響應鍊另一半:當hitTest接收到能夠響應事件的view後,window會将消息傳給UIApplication,傳回傳回view就不做任何處理。
兄弟view是先檢測第一個view還是檢測最後添加的view——推理應該是檢測最後添加的view。
可以去github上檢視Demo,喜歡的話star一下哦
github
CSDN