前沿
在學(xué)習(xí)事件傳遞以及響應(yīng)之前,我們先來了解一下UIView與Calayer的關(guān)系。一個(gè)View包含有響應(yīng)的calayer以及backGround. 而calayer中content只負(fù)責(zé)內(nèi)容的顯示,而View負(fù)責(zé)提供給 calayer顯示的內(nèi)容,該內(nèi)容是以一個(gè)位圖來顯示的,如圖中的backing store就是一個(gè)位圖。它們的這種功能方式,正式與單一職責(zé)的原則相符。

一、事件傳遞
(1)所涉及到的方法:
- 返回響應(yīng)的View
-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event; - 點(diǎn)擊的位置是否當(dāng)前范圍內(nèi),如果是,返回YES,否則 NO
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event;
(2)事件傳遞流程:

當(dāng)我們點(diǎn)擊到屏幕的某個(gè)位置的時(shí)候,事件首先會(huì)傳遞給UIApplication,接著,又會(huì)傳遞給UIWindow,UIWindow就會(huì)判斷hitTest:withEvent:來返回最終的視圖,在這個(gè)方法的內(nèi)部實(shí)際上會(huì)調(diào)用pointInside:withEvent:方法,判斷點(diǎn)擊的位置是否在UIWindow范圍內(nèi),如果是,它會(huì)遍歷它的子視圖,來查找最終的響應(yīng)視圖。而遍歷的方式是以倒序遍歷的方式,也就是說,最后添加到window的視圖,會(huì)最優(yōu)先遍歷到,而在遍歷到的每一個(gè)UIView 它都會(huì)調(diào)用hit=[sub hitTest:withEvent:]方法,我們可看作是一個(gè)遞歸調(diào)用。而這個(gè)hit方法,最終會(huì)返回一個(gè)最終的響應(yīng)視圖。如果返回的hit!=nil,則這個(gè)hit會(huì)作為最終的響應(yīng)視圖。如果沒有,并且在window的范圍內(nèi),則會(huì)將window看作最終的響應(yīng)視圖。以上就是一個(gè)完整的事件傳遞流程。下面我們來以一個(gè)流程圖,來看一下hitTest方法的內(nèi)部實(shí)現(xiàn)。
(3)hitTest:withEvent:方法的內(nèi)部實(shí)現(xiàn)

了解的該方法的內(nèi)部實(shí)現(xiàn),我們就可以在該方法中作出自己的想要的業(yè)務(wù)邏輯處理,比如說,我要更改按鈕的點(diǎn)擊區(qū)域。比如:制作形狀是方形、點(diǎn)擊區(qū)域是圓形的按鈕。Demo
(4)事件響應(yīng)的流程:

以button為例,當(dāng)我們點(diǎn)擊了按鈕之后,最先交給的它的父視圖做處理,如果父視圖不做處理,事件就會(huì)想向上傳遞,直到有視圖或者controller 作出事件處理。否則,它會(huì)一直傳遞下去(view->controller(如果存在,就會(huì)傳遞給controller,不存在就直接傳遞給window)->window->application->applicationDelegate)。如果,傳遞到applicationDelegate仍沒有對(duì)該事件作出處理,那么該事件就會(huì)被丟棄,不做響應(yīng)。
(5)所涉及到的方法:
- -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- -(void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;
- -(void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event;