iOS響應(yīng)者鏈

先來(lái)明確幾個(gè)概念
  1. 響應(yīng)者對(duì)象
    可以進(jìn)行事件處理的對(duì)象。用戶進(jìn)行了某個(gè)操作,系統(tǒng)會(huì)將該操作包裝成一個(gè)Event事件對(duì)象交與響應(yīng)者對(duì)象進(jìn)行處理
  2. 事件傳遞
    如果第一響應(yīng)者對(duì)象沒(méi)有處理該事件,系統(tǒng)就會(huì)將它轉(zhuǎn)發(fā)到下一個(gè)響應(yīng)者對(duì)象那里處理,這個(gè)尋找的過(guò)程就成為事件傳遞
  3. 事件隊(duì)列
    操作被包裝成事件之后,會(huì)先放入當(dāng)前活動(dòng)的Application事件隊(duì)列中,單例的UIApplication會(huì)從事件隊(duì)列中依次取出事件并交給單例的UIWindow來(lái)處理,UIWindow對(duì)象首先會(huì)尋找此次操作的初始點(diǎn)所在的view
  4. 響應(yīng)鏈
    進(jìn)行事件傳遞的由一系列響應(yīng)者對(duì)象組成的層次結(jié)構(gòu)就稱為響應(yīng)者鏈
  5. 涉及到的方法 :hitTest:withEvent:
    命中測(cè)試方法,該方法用于尋找第一響應(yīng)者的過(guò)程中。返回值類型是UIView,表示當(dāng)前事件觸發(fā)的點(diǎn)在哪個(gè)view的范圍內(nèi)。hitTest方法的返回值,表示當(dāng)前視圖層級(jí)最低層的符合條件的視圖。比如,Aview的子視圖是Bview,點(diǎn)擊了Bview,雖然這個(gè)點(diǎn)也在Aview范圍內(nèi),但是hitTest會(huì)繼續(xù)向它的子視圖Bview進(jìn)行查找,最終hitTest返回的是Bview
    該方法的point參數(shù)是相對(duì)于接收者的坐標(biāo)系的,其內(nèi)部會(huì)首先調(diào)用pointInside:withEvent: 方法,
  6. 涉及到的方法:pointInside:withEvent:
    該方法的返回值類型為布爾型,判斷參數(shù)中的點(diǎn)是否在當(dāng)前所在view范圍內(nèi)。官方對(duì)該方法的注釋是:default returns YES if point is in bounds
  7. 第一響應(yīng)者
    如5所說(shuō),雖然Aview和Bview都可以是點(diǎn)擊事件的響應(yīng)者,但系統(tǒng)只會(huì)將該事件交與最底層的Bview進(jìn)行處理,此時(shí)Bview就稱為第一響應(yīng)者
事件處理的過(guò)程

先將事件對(duì)象由父控件傳遞給子控件,找到最合適的控件來(lái)處理這個(gè)事件。 調(diào)用最合適控件的touches….方法 如果調(diào)用了[super touches….];就會(huì)將事件順著響應(yīng)者鏈條往上傳遞,傳遞給上一個(gè)響應(yīng)者 接著就會(huì)調(diào)用上一個(gè)響應(yīng)者的touches….方法。
如果view是控制器的view,就傳遞給控制器;如不是,則將其傳遞給它的父視圖 在視圖層次結(jié)構(gòu)的最頂級(jí)視圖,如果也不能處理收到的事件或消息,則其將事件或消息傳遞給window對(duì)象進(jìn)行處理 如果window對(duì)象也不處理,則其將事件或消息傳遞給UIApplication對(duì)象 如果UIApplication也不能處理該事件或消息,則該事件會(huì)被丟棄,不能被處理

另外,在遍歷子控件的時(shí)候,是從子控件數(shù)組中最后一個(gè)元素開(kāi)始使用hitTest進(jìn)行判斷

兩個(gè)方法的內(nèi)部實(shí)現(xiàn)

大概的內(nèi)部實(shí)現(xiàn),只是為了方便理解

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event{  
    UIView *touchView = self;  
    // 事件發(fā)生點(diǎn)在當(dāng)前view范圍內(nèi),接著查詢是否在子view范圍內(nèi)
    if ([self pointInside:point withEvent:event]) {  
        for (UIView *subView in self.subviews) {   
            // 轉(zhuǎn)換下坐標(biāo),
            CGPoint subPoint = CGPointMake(point.x - subView.frame.origin.x,  
                                           point.y - subView.frame.origin.y);  
            // 調(diào)用自身方法檢查子view
            UIView *subTouchView = [subView hitTest:subPoint withEvent:event];  
            if (subTouchView) {  
                //找到touch事件對(duì)應(yīng)的view,停止遍歷  
                touchView = subTouchView;  
                break;  
            }  
              // 如果所有子視圖的hitTest都返回nil,則該方法直接返回self
        }  
    }else{  
        //不在該View范圍內(nèi),直接返回nil,不會(huì)再繼續(xù)查詢子view的情況
        touchView = nil;  
    }  
     
    return touchView;  
}  
  
- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{  
    return CGRectContainsPoint(self.bounds, point);  
}  
hitTest方法被忽略的情況
  1. 隱藏(hidden=YES)
  2. 禁止用戶操作(userInteractionEnabled=NO)
  3. alpha小于0.01
  4. 如果一個(gè)子視圖的區(qū)域超過(guò)父視圖的bound區(qū)域,雖然該子視圖內(nèi)容可以顯示,卻無(wú)法響應(yīng)事件
應(yīng)用
  1. 讓超出父view范圍的子view同樣可以響應(yīng)事件:超出范圍的子view之所以不能響應(yīng)事件,是因?yàn)楦敢晥D的pointInside方法返回了NO,只要重寫該方法,在方法內(nèi)部判斷需要響應(yīng)的范圍就可以了
  2. 同一個(gè)view,一部分范圍可以響應(yīng)事件,一部分范圍不可以響應(yīng)事件。比如要做一些不規(guī)則形狀的控件,控件之間有重合的部分,需求希望只有在點(diǎn)擊不重合的部分時(shí)才響應(yīng)事件,點(diǎn)擊重合部分不要有響應(yīng)。此時(shí)可以重寫該view的pointInside方法,同樣在內(nèi)部判斷響應(yīng)事件的范圍
  3. 讓一個(gè)view的子view都不能響應(yīng)事件:重寫該view的pointInside方法,直接返回NO
  4. 讓一個(gè)view自身以及它的子view都不能響應(yīng)事件:重寫該view的hitTest方法,直接返回nil(當(dāng)然有很多其他更簡(jiǎn)便的方式)
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 一篇搞定事件傳遞、響應(yīng)者鏈條、hitTest和pointInside的使用發(fā)生觸摸事件后,系統(tǒng)會(huì)將該事件加入到一個(gè)...
    克魯?shù)吕?/span>閱讀 1,200評(píng)論 0 1
  • 一、響應(yīng)者鏈(Responder Chain) 先來(lái)說(shuō)說(shuō)響應(yīng)者對(duì)象(Responder Object),顧名思義,...
    像小強(qiáng)一樣活著閱讀 6,955評(píng)論 8 76
  • 1、響應(yīng)鏈的傳遞 Responder一點(diǎn)也不神秘————iOS用戶響應(yīng)者鏈完全剖析(建議全看)看完上面一篇應(yīng)該能完...
    RasonWu閱讀 10,516評(píng)論 3 36
  • 響應(yīng)者鏈顧名思義就是由一系列能夠響應(yīng)事件的響應(yīng)者對(duì)象組成的一個(gè)層式結(jié)構(gòu)。我們把具有響應(yīng)和處理事件能力的對(duì)象稱為響應(yīng)...
    Nicole__Zhang閱讀 484評(píng)論 0 2
  • 希望你給的愛(ài) 安穩(wěn)而漫長(zhǎng) 畢竟 這是我以后賴以為生的東西啊
    _心和_閱讀 163評(píng)論 0 0

友情鏈接更多精彩內(nèi)容