ViewTouch事件以及其傳遞

面試被問(wèn)到了一個(gè)Button,如果點(diǎn)擊無(wú)效果,你會(huì)怎么排查? 這個(gè)問(wèn)題我當(dāng)時(shí)回答的比較簡(jiǎn)單,但是面試官追問(wèn)的比較深,我回答的有些含糊,課后補(bǔ)習(xí)一下。

前言:

借鑒了一些簡(jiǎn)書(shū)大佬的文章的文章,然后自己寫了Demo,測(cè)試完畢后自己總結(jié)下自己的理解。


iOS中的事件可以分為3大類型:觸摸事件-加速計(jì)事件-遠(yuǎn)程控制事件。

此文只針對(duì)觸摸事件。

查看源碼可以很輕易發(fā)現(xiàn):

UIViewController繼承關(guān)系
UIView繼承關(guān)系
UIWindow繼承關(guān)系
UIApplication繼承關(guān)系

由此可見(jiàn):UIViewController - UIView - UIWindow - UIApplication都是繼承UIResponder,那UIResponder又是什么呢,圖中都繼承UIResponder,能代表又有什么結(jié)論呢?

先說(shuō)說(shuō)UIResponder。

在iOS中UIResponder類是專門用來(lái)響應(yīng)用戶的操作處理各種事件的,包括觸摸事件(Touch Events)、運(yùn)動(dòng)事件(Motion Events)、遠(yuǎn)程控制事件(Remote Control Events)。具體的UIResponder內(nèi)部又是如何處理事件,這里不做說(shuō)明。

查看UIResponder源碼可以發(fā)現(xiàn):

UIResponder事件官方

由此可見(jiàn),官方讓我們重新這幾個(gè)方法,就可以實(shí)現(xiàn)觸摸相關(guān)的活動(dòng)事件。

UIView,UIApplication,UIWindow,UIViewController繼承UIResponder,同樣具有父類的這些觸摸事件。

這里以UIViewController和UIView為例,其他的道理是相同的。

在UIViewController重新touchesBegan方法,點(diǎn)擊當(dāng)前的Controller,

直接上代碼,因?yàn)榇a比較簡(jiǎn)單,我就截圖說(shuō)明。

在UIViewController實(shí)現(xiàn)touchesBegan方法

觸摸事件參數(shù)有兩個(gè)UITouch,UIEvent,兩個(gè)參數(shù)有著自己不同的任務(wù)。

UITouch

當(dāng)用戶用一根手指觸摸屏幕時(shí),會(huì)創(chuàng)建一個(gè)與手指相關(guān)的UITouch對(duì)象.

UITouch對(duì)象,封裝了當(dāng)前的Touch事件的對(duì)象集合。

UITouchd對(duì)象的屬性官方介紹

Touch對(duì)象保存著跟手指相關(guān)的信息,比如觸摸的位置、時(shí)間、階段

當(dāng)手指移動(dòng)時(shí),系統(tǒng)會(huì)更新同一個(gè)UITouch對(duì)象,使之能夠一直保存該手指在的觸摸位置

當(dāng)手指離開(kāi)屏幕時(shí),系統(tǒng)會(huì)銷毀相應(yīng)的UITouch對(duì)象。

重寫:touchesBegan

點(diǎn)擊一次,當(dāng)前操作只有一次,所以Set集合只有一個(gè)Touch事件,而且事件tap count = 1。(單擊事件)。

重寫:touchesMoved

隨著手指的拖動(dòng),set集合的Touch對(duì)象會(huì)隨之拖到而改變,且此時(shí)的Touch對(duì)象是不一樣的,當(dāng)前移動(dòng)的位置和上一次不一樣。

正因?yàn)槭种冈诓粩嗟囊苿?dòng),所以當(dāng)前的點(diǎn)和上次移動(dòng)的點(diǎn),官方也給了相關(guān)方法來(lái)獲取。

獲取當(dāng)前手指移動(dòng)和上次移動(dòng)的點(diǎn)

?UIEvent

UIEvent事件

觸摸的目的是生成觸摸事件供響應(yīng)者響應(yīng),一個(gè)觸摸事件(UITouch)對(duì)應(yīng)一個(gè)UIEvent對(duì)象,其中的type屬性標(biāo)識(shí)了事件的類型,事件有如下幾種類型:

根據(jù)手勢(shì)的不同操作(單擊,滑動(dòng),按壓,平移等動(dòng)作),所出發(fā)的事件效果會(huì)不同。

枚舉事件類型

回到前面說(shuō)的Button的案例。

有個(gè)UIButton,Button的點(diǎn)擊事件我們也實(shí)現(xiàn)了,卻點(diǎn)擊無(wú)效,無(wú)法響應(yīng)與之對(duì)應(yīng)的點(diǎn)擊方法,這時(shí)候我們?cè)撊绾稳ゲ椋?/p>

一般都會(huì)檢查自己寫addTarget是否有誤,點(diǎn)擊事件ButtonClick是否實(shí)現(xiàn)。

其次我們也可以從View的事件傳遞考慮。

View事件傳遞有三個(gè)原則不會(huì)傳遞:

1.當(dāng)前View或者控件的userInteractionEnabled = NO;

2.當(dāng)前View或者控件的Hidden為YES

3.同理當(dāng)前View或者控件透明的<=0.01,也就是(0-0.01)。

除此之外,我們也可以通過(guò)重寫View的hitTest來(lái)查看當(dāng)前事件可傳遞的View。

View的hitTest方法

這里使用下比較經(jīng)典的一個(gè)圖解:

事件傳遞

舉例:

點(diǎn)擊黃色View,因?yàn)槲覀儾](méi)有寫以上阻斷事件傳遞的三種方式,所以黃色的父控件(藍(lán)色),父父控件(橙色),以及父父父控件(白色)打印的結(jié)果都是一直的,指向黃色View。

應(yīng)用如何找到最合適的控件來(lái)處理事件?

1.首先判斷主窗口(keyWindow)自己是否能接受觸摸事件

2.觸摸點(diǎn)是否在自己身上

3.從后往前遍歷子控件,重復(fù)前面的兩個(gè)步驟(首先查找數(shù)組中最后一個(gè)元素)

4.如果沒(méi)有符合條件的子控件,那么就認(rèn)為自己最合適處理


上面的說(shuō)法是比較官方的解釋,用比較通俗的解釋就是說(shuō):

UIApplication 問(wèn) keyWindow?:小子,我給你個(gè)事件你能不能處理下?

keyWindow唯唯諾諾的說(shuō):我。。我不能,觸摸點(diǎn)不在我身上。

keyWindow 又去問(wèn)它的子控件橙色View。

keyWindow:小橙,老大安排了事情,我不能處理,你小子能不能給處理這個(gè)點(diǎn)擊事件?

OrangeView同樣唯唯諾諾的說(shuō):我不能,觸摸點(diǎn)不在我身上。

。。。。。。

直到最后一層黃色View。

OrangeView:沒(méi)問(wèn)題啦~觸摸點(diǎn)在我身上,老大們放心吧,我會(huì)處理好的(觸摸事件里的操作)。

大概用比較歡喜的理解就是這樣傳遞。

特殊情況:

hitTest:withEvent:中return nil的意思是調(diào)用當(dāng)前hitTest:withEvent:方法的view不是合適的view,子控件也不是合適的view。如果同級(jí)的兄弟控件也沒(méi)有合適的view,那么最合適的view就是父控件。

1.所有的子控件都有攔截事件傳遞的情況,比如都給攔截掉了。

你們他們最終的父控件會(huì)返回nil,代表沒(méi)有其子控件可以處理,只能自己處理了。

子控件打?。?/p>

父控件會(huì)返回nil情況

父控件打印:

GrayView其實(shí)就是上圖的1白色,我demo命名不同

代表只能自己去處理這個(gè)事件。

其次還需要一點(diǎn)說(shuō)明,如果1234中的某個(gè)view攔截事件了,就不會(huì)傳遞給其子控件啦。

3有攔截事件功能,4就不能操作這個(gè)事件,只能是3的父,父父,父父父View來(lái)處理。


以上就是我對(duì)View事件和傳遞的自己的理解,記錄一下,作為知識(shí)點(diǎn)儲(chǔ)存。

如果有誤或者更好的理解,望大家留言,謝謝。

?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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