天天看點

iOS基礎06—--事件響應鍊

iOS基礎06——事件響應鍊

移動應用的最大特性就是響應使用者互動操作,那麼iOS系統是如何去響應一個簡單的點選事件的呢?系統如何精準地定位一個事件的響應者呢?

首先一個事件産生後,系統會将其包裝成一個uievent和uitouch對象,然後傳給目前的app!目前app一級一級查找響應者的規程就形成了一個事件響應鍊!

事件傳遞進來時,uiapplication會将事件放置到隊列中,然後會從隊列中取出事件傳遞給keywindow!注意每一個view都含有以下兩個方法:

1、擷取到響應事件的view,然後傳遞回去;

[hittest:withevent:]
           

2、判斷事件是否在目前view的範圍裡!

[pointinside:withevent:]
           

具體的實作如下圖

iOS基礎06—--事件響應鍊

widow會先檢視點選事件是否在自己的範圍内,如果是,就會繼續查詢子視圖!如圖所示,如果目前視圖滿足要求就會繼續查找目前視圖的子視圖,否則會查找同等級的兄弟視圖,依次類推,直到查到為止。

舉個例子:

iOS基礎06—--事件響應鍊

如果在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