事件的產(chǎn)生和傳遞過程:
1.發(fā)生觸摸事件后,系統(tǒng)會(huì)將該事件加入到一個(gè)由UIApplication管理的隊(duì)列事件中
2.UIApplication會(huì)從事件隊(duì)列中取出最前面的事件,并將事件分發(fā)下去以便處理,通常會(huì)先發(fā)送事件給應(yīng)用程序的主窗口(keyWindow)
3.主窗口會(huì)在視圖層次結(jié)構(gòu)中找到一個(gè)最合適的視圖來處理觸摸事件
4.找到合適的視圖控件后,就會(huì)調(diào)用視圖控件的touches方法來作事件的具體處理:touchesBegin… touchesMoved…touchesEnded等
5.這些touches方法默認(rèn)的做法是將事件順著響應(yīng)者鏈條向上傳遞,將事件叫個(gè)上一個(gè)相應(yīng)者進(jìn)行處理
一般事件的傳遞是從父控件傳遞到子控件的
如果父控件接受不到觸摸事件,那么子控件就不可能接收到觸摸事件 UIView不能接收觸摸事件的三種情況:
1.不接受用戶交互:userInteractionEnabled = NO;
2.隱藏:hidden = YES;
3.透明:alpha = 0.0~0.01
用戶的觸摸事件首先會(huì)由系統(tǒng)截獲,進(jìn)行包裝處理等。? 然后遞歸遍歷所有的view,進(jìn)行碰觸測(cè)試(hitTest),直到找到可以處理事件的view。? - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event;// recursively calls -pointInside:withEvent:. point is in the receiver's coordinate system ?
該方法會(huì)首先在application的keyWindow上調(diào)用(UIWindow也是UIView的子類),并且該方法的返回值將被用來處理事件。如果這個(gè)view(無論是window還是普通的UIView) 的userInteractionEnabled屬性被設(shè)置為NO,則它的hitTest:永遠(yuǎn)返回nil,這意味著它和它的子視圖沒有機(jī)會(huì)去接收和處理事件。如果userInteractionEnabled屬性為YES,則會(huì)通過該方法- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;// default returns YES if point is in bounds先判斷產(chǎn)生觸摸的point是否發(fā)生在自己的bounds內(nèi),如果沒有也將返回nil;如果point在自己的范圍內(nèi),則會(huì)為自己的每個(gè)子視圖調(diào)用hitTest:方法,只要有一個(gè)子視圖通過這個(gè)方法返回一個(gè)UIView對(duì)象,那么整個(gè)方法就一層一層地往上返回;如果沒有子視圖返回UIView對(duì)象,則父視圖將會(huì)把自己返回。
大致的過程application –> window –> root view –>……–>lowest view
響應(yīng)者鏈
響應(yīng)者鏈條其實(shí)就是很多響應(yīng)者對(duì)象(繼承自UIResponder的對(duì)象)一起組合起來的鏈條稱之為響應(yīng)者鏈條
一般默認(rèn)做法是控件將事件順著響應(yīng)者鏈條向上傳遞,將事件交給上一個(gè)響應(yīng)者進(jìn)行處理。那么如何判斷當(dāng)前響應(yīng)者的上一個(gè)響應(yīng)者是誰呢?有以下兩個(gè)規(guī)則:
1.判斷當(dāng)前是否是控制器的View,如果是控制器的View,上一個(gè)響應(yīng)者就是控制器
2.如果不是控制器的View,上一個(gè)響應(yīng)者就是父控件
當(dāng)有view能夠處理觸摸事件后,開始響應(yīng)事件。 系統(tǒng)會(huì)調(diào)用view的以下方法:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;? - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;? - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;? - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;? 可以多對(duì)象共同響應(yīng)事件。只需要在以上方法重載中調(diào)用super的方法。? 大致的過程initial view –>super view –> …..–> view controller –> window –> Application? 需要特別注意的一點(diǎn)是,傳遞鏈中時(shí)沒有controller的,因?yàn)閏ontroller本身不具有大小的概念。但是響應(yīng)鏈中是有controller的,因?yàn)閏ontroller繼承自UIResponder。
UIApplication–>UIWindow–>遞歸找到最合適處理的控件–>控件調(diào)用touches方法–>判斷是 否實(shí)現(xiàn)touches方法–>沒有實(shí)現(xiàn)默認(rèn)會(huì)將事件傳遞給上一個(gè)響應(yīng)者–>找到上一個(gè)響應(yīng)者–>找不到方法作廢
PS:利用響應(yīng)者鏈條我們可以通過調(diào)用touches的super 方法,讓多個(gè)響應(yīng)者同時(shí)響應(yīng)該事件。