首先參考響應(yīng)者鏈條 http://www.reibang.com/p/c294d1bd963d
系統(tǒng)響應(yīng)
- 首先 屏幕接收到點(diǎn)擊后在孝,IOKit會(huì)進(jìn)行事件捕捉
- 而后通過(guò) mach port傳遞給SpringBoad進(jìn)程
- SpringBoard進(jìn)程因接收到觸摸事件继榆,觸發(fā)了主線程runloop的source1事件源的回調(diào)
- 如果此時(shí)在桌面,則交給桌面系統(tǒng)去消耗該事件
- 如果此時(shí)在app前臺(tái),則通過(guò)IPC(進(jìn)程通信)傳給app進(jìn)程
APP響應(yīng)
- 通過(guò) mach port收到SpringBoad的觸摸事件,主線程runloop被喚醒驻仅,觸發(fā)source1回調(diào)
- source1回調(diào)觸發(fā)soirce0回調(diào)嬉挡,將觸摸事件封成UIEvent事件
- source0將事件添加到UIApplication對(duì)象的隊(duì)列中丰泊,開(kāi)始尋找最佳響應(yīng)者h(yuǎn)it-testing
- 尋找到最佳響應(yīng)者后,開(kāi)始事件的響應(yīng)在響應(yīng)鏈中的傳遞和響應(yīng)
- 觸摸事件要么被某個(gè)響應(yīng)對(duì)象捕獲后釋放隙轻,要么無(wú)法找到響應(yīng)對(duì)象后釋放
hit-Testing
- UIApplication 通過(guò) 調(diào)用UIWindow的 hitTest:withEvent: 傳遞給UIWindow埠帕,依次從后往前遍歷子視圖傳遞
- 過(guò)程
- 判斷是否可交互
- 不允許交互:userInteractionEnabled = NO
- 隱藏:hidden = YES 如果父視圖隱藏,那么子視圖也會(huì)隱藏大脉,隱藏的視圖無(wú)法接收事件
- 透明度:alpha < 0.01 如果設(shè)置一個(gè)視圖的透明度<0.01搞监,會(huì)直接影響子視圖的透明度。alpha:0.0~0.01為透明镰矿。
- 判斷是否在視圖中 if ([self pointInside:point withEvent:event] == NO) return nil;
- 判斷是否在子視圖中 CGPoint childP = [self convertPoint:point toView:childView];
UIView *fitView = [childView hitTest:childP withEvent:event]; - 重寫(xiě)父視圖 - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 可以實(shí)現(xiàn)超出點(diǎn)擊
- 判斷是否可交互
事件響應(yīng)
- 事件的最佳響應(yīng)者是 hit-tested view琐驴,他可以獨(dú)吞事件 也可以往后傳遞
- 不操作默認(rèn)往下分發(fā),通過(guò)nextResponder
- 在 touchesMoved: withEvent: 是否調(diào)用父類同名方法決定是否往下分發(fā)
事件優(yōu)先級(jí) UIResponder秤标、UIGestureRecognizer绝淡、UIControl
UIResponder 和 UIGestureRecognizer
- 如果成功識(shí)別了 UIGestureRecognizer 則 優(yōu)先進(jìn)行 手勢(shì),而中止 hit-tested view的 UIResponder 過(guò)程苍姜。
- 觸摸狀態(tài)變化 的 begin 先發(fā)送到 手勢(shì) 再 hit-tested
- 順序?yàn)?手勢(shì)begin —— hit-test begin—— 手勢(shì)識(shí)別成功——手勢(shì)end ——hit-test cancel
- 屬性:cancelsTouchesInView 牢酵。默認(rèn)YES,代表手勢(shì)成功后衙猪,屏蔽響應(yīng)鏈的響應(yīng)
- 屬性:delaysTouchesBegan 馍乙。默認(rèn)NO,代表在手勢(shì)識(shí)別期間不會(huì)調(diào)用 hit-test begin垫释,move等
- 屬性:delaysTouchesEnded 丝格。默認(rèn)YES,代表手勢(shì)失敗后棵譬,會(huì)延遲0.15s調(diào)用響應(yīng)者的 touchesEnded:withEvent:显蝌,若NO,立即調(diào)用
UIControl
- (BOOL)beginTrackingWithTouch:(UITouch *)touch withEvent:(nullable UIEvent *)event;
- (BOOL)continueTrackingWithTouch:(UITouch *)touch withEvent:(nullable UIEvent *)event;
- (void)endTrackingWithTouch:(nullable UITouch *)touch withEvent:(nullable UIEvent *)event;
- (void)cancelTrackingWithEvent:(nullable UIEvent *)event;
這幾個(gè)方法是在 touch 系列里面調(diào)用的
- UIControl會(huì)阻止父視圖上的手勢(shì)識(shí)別器行為订咸,也就是UIControl處理事件的優(yōu)先級(jí)比UIGestureRecognizer高曼尊,但前提是相比于父視圖上的手勢(shì)識(shí)別器。
- UIControl比其父視圖上的手勢(shì)識(shí)別器具有更高的事件響應(yīng)優(yōu)先級(jí)脏嚷。
- 準(zhǔn)確地說(shuō)只適用于系統(tǒng)提供的有默認(rèn)action操作的UIControl骆撇,例如UIbutton、UISwitch等的單擊
UIResponser
一:響應(yīng)者鏈 UIResponser包括了各種Touch message 的處理然眼,比如開(kāi)始艾船,移動(dòng)葵腹,停止等等。常見(jiàn)的 UIResponser 有 UIView及子類屿岂,UIViController,APPDelegate践宴,UIApplication等等。
回到響應(yīng)鏈爷怀,響應(yīng)鏈?zhǔn)怯蒛IResponser組成的阻肩,那么是按照哪種規(guī)則形成的。
A: 程序啟動(dòng) UIApplication會(huì)生成一個(gè)單例运授,并會(huì)關(guān)聯(lián)一個(gè)APPDelegate烤惊。APPDelegate作為整個(gè)響應(yīng)鏈的根建立起來(lái),而``UIApplication會(huì)將自己與這個(gè)單例鏈接吁朦,即UIApplication的nextResponser(下一個(gè)事件處理者)為APPDelegate`柒室。
B:創(chuàng)建UIWindow 程序啟動(dòng)后,任何的UIWindow被創(chuàng)建時(shí)逗宜,UIWindow內(nèi)部都會(huì)把nextResponser設(shè)置為UIApplication單例雄右。UIWindow初始化rootViewController,rootViewController的nextResponser會(huì)設(shè)置為UIWindow
C:UIViewController初始化 loadView, VC的view的nextResponser會(huì)被設(shè)置為VC.
D:addSubView addSubView操作過(guò)程中,如果子subView不是VC的View,那么subView的nextResponser會(huì)被設(shè)置為superView纺讲。如果是VC的View,那就是 subView -> subView.VC ->superView如果在中途擂仍,subView.VC被釋放,就會(huì)變成subView.nextResponser = superView