1. 程式人生 > >iOS基礎06—--事件響應鏈

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

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