你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 響應者鏈及相關機制總結

響應者鏈及相關機制總結

編輯:IOS開發基礎

1467190927314559.jpg

概念

響應者:對用戶交互動作事件進行響應的對象。

響應者鏈:成為處理事件的響應者的先後順序鏈。

正文

1、Hit-Test 機制

當用戶觸摸(Touch)屏幕進行交互時,系統首先要找到響應者(Responder)。系統檢測到手指觸摸(Touch)操作時,將Touch 以UIEvent的方式加入UIApplication事件隊列中。UIApplication從事件隊列中取出最新的觸摸事件進行分發傳遞到UIWindow進行處理。UIWindow 會通過hitTest:withEvent:方法尋找觸碰點所在的視圖,這個過程稱之為hit-test view。

hitTest 的順序如下

UIApplication -> UIWindow -> Root View -> ··· -> subview

在頂級視圖(Root View)上調用pointInside:withEvent:方法判斷觸摸點是否在當前視圖內;

如果返回NO,那麼hitTest:withEvent:返回nil;

如果返回YES,那麼它會向當前視圖的所有子視圖發送hitTest:withEvent:消息,所有子視圖的遍歷順序是從最頂層視圖一直到到最底層視圖,即從subviews數組的末尾向前遍歷,直到有子視圖返回非空對象或者全部子視圖遍歷完畢。

如果有subview的hitTest:withEvent:返回非空對象則A返回此對象,處理結束(注意這個過程,子視圖也是根據pointInside:withEvent:的返回值來確定是返回空還是當前子視圖對象的。並且這個過程中如果子視圖的hidden=YES、userInteractionEnabled=NO或者alpha小於0.1都會並忽略);

如果所有subview遍歷結束仍然沒有返回非空對象,則hitTest:withEvent:返回self;

系統就是這樣通過hit test找到觸碰到的視圖(Initial View)進行響應。

2、響應者鏈 (Responder Chain)

有些時候,Touch後系統通過hit test 機制找到了觸碰到的Initial View,但是Initial view並沒有或者無法正常處理此次Touch。這個時候,系統便會通過響應者鏈尋找下一個響應者,以對此次Touc 進行響應。

響應者鏈順序如下:

Initial View -> View Controller(如果存在) -> superview -> · ··  -> rootView -> UIWindow -> UIApplication

0064cTs2gw1f5btrssp5mj306y07dweh.jpg

示意圖

如果一個View有一個視圖控制器(View Controller),它的下一個響應者是這個視圖控制器,緊接著才是它的父視圖(Super View),如果一直到Root View都沒有處理這個事件,事件會傳遞到UIWindow(iOS中有一個單例Window),此時Window如果也沒有處理事件,便進入UIApplication,UIApplication是一個響應者鏈的終點,它的下一個響應者指向nil,以結束整個循環。

3、實際開發中常見的相關問題

在實際開發中,經常會遇到視圖沒有響應的情況,特別是新手會經常搞不清楚狀況。

一下是視圖沒有響應的幾個情況:

1.userInteractionEnabled=NO;

2.hidden=YES;

3.alpha=0~0.01;

4.沒有實現touchesBegan:withEvent:方法,直接執行touchesMove:withEvent:等方法;

5.目標視圖點擊區域不在父視圖的Frame上 (superView背景色為clear Color的時候經常會忽略這個問題)。

在某些情景下,我們在點擊子視圖的時候仍然需要調用父視圖的touchesBegan:withEvent:等方法,例如我們在父視圖上添加了一個覆蓋范圍了父視圖大部分面積的TableView或ScrollerView 或其他View,而我們要通過父視圖的touchesBegan:withEvent:方法來收鍵盤。

這個時候我們可以通過UIView的類別,重寫touch相關方法,代碼如下:

-(void)setEnableNextResponder:(BOOL)enableNextResponder {
    objc_setAssociatedObject(self, &enableNextResponderKey, enableNextResponderKey, OBJC_ASSOCIATION_ASSIGN);
}
-(BOOL)enableNextResponder {
    return objc_getAssociatedObject(self, &enableNextResponderKey);
}
-(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    if (self.enableNextResponder) {
        [[self nextResponder] touchesBegan:touches withEvent:event];
        [super touchesBegan:touches withEvent:event];
    }
}
-(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    if (self.enableNextResponder) {
        [[self nextResponder] touchesEnded:touches withEvent:event];
        [super touchesEnded:touches withEvent:event];
    }
}
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
    if (self.enableNextResponder) {
        [[self nextResponder] touchesMoved:touches withEvent:event];
        [super touchesMoved:touches withEvent:event];
    }
}
-(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event {
    if (self.enableNextResponder) {
        [[self nextResponder] touchesCancelled:touches withEvent:event];
        [super touchesCancelled:touches withEvent:event];
    }
}

我在我的github:WXSTools 放了個平時寫來自己用的部分工具類的集合,裡面的UIView+Touch可以作為Demo代碼。

本文作者: 伯樂在線 - alanwangmodify 

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved