iOS 事件的傳遞和響應機制

聲明:

這篇是根據看史上最詳細的iOSZ之事件的傳遞和響應機制-原理篇做的一個筆記褐奴。

筆記一:響應者對象(UIResponder)

UIResponder類可以接收和處理事件因為它提供了4個對象方法來處理接觸事件

UIResponder內部提供了以下方法來處理事件觸摸事件

// 一根或者多根手指開始觸摸view敦冬,系統(tǒng)會自動調用view的下面方法
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;

// 一根或者多根手指在view上移動,系統(tǒng)會自動調用view的下面方法(隨著手指的移動脖旱,會持續(xù)調用該方法)
- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;

// 一根或者多根手指離開view,系統(tǒng)會自動調用view的下面方法
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;

//觸摸結束前
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

其他事件:
加速計事件
- (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event;
- (void)motionCancelled:(UIEventSubtype)motion withEvent:(UIEvent *)event;
遠程控制事件
- (void)remoteControlReceivedWithEvent:(UIEvent *)event;

總結:
UIApplication蚤氏,UIViewController踊兜,UIView都是繼承于UIResponder捏境,所以它們也可以重寫事件來接收和處理事件毁葱。

聯(lián)想:
CALayer 和 UIView的最大區(qū)別是 UIview可以處理事件 因為view是responder的子類

筆記二:UITouch對象

下面是UITouch的屬性和方法:

 @interface UITouch : NSObject

NSTimeInterval   timestamp; //觸摸發(fā)生的時間
UITouchPhase        phase;  //返回一個階段常量,指出觸摸開始倾剿、繼續(xù)前痘、結束或被取消,分別對應UITouchPhaseBegan芹缔、UITouchPhaseMoved等
NSUInteger          tapCount;   //輕按屏幕的次數(shù) 可以根據這個判斷單擊 雙擊 多擊
UITouchType         type NS_AVAILABLE_IOS(9_0); //觸摸的類型

CGFloat majorRadius ; //觸摸的半徑
CGFloat majorRadiusTolerance;//觸摸的半徑的誤差值

//引起觸摸的視圖或Window.
UIWindow   *window;
UIView        *view;

NSArray <UIGestureRecognizer *> *gestureRecognizers ;//手勢數(shù)組
//  現(xiàn)在觸摸的坐標//函數(shù)返回一個CGPoint類型的值最欠,
//  表示觸摸在view這個視圖上的位置惩猫,這里返回的位置是針對view的坐標系的蚜点。
//  調用時傳入的view參數(shù)為空的話,返回的時觸摸點在整個窗口的位置禽额。
- (CGPoint)locationInView:(nullable UIView *)view;

//上一次觸摸的坐標//該方法記錄了前一個坐標值函數(shù)返回也是一個CGPoint類型的值
//表示觸摸在view這個視圖上的位置脯倒,這里返回的位置是針對view的坐標系的。
//調用時傳入的view參數(shù)為空的話藻丢,返回的時觸摸點在整個窗口的位置。
- (CGPoint)previousLocationInView:(nullable UIView *)view;

////現(xiàn)在觸摸的精確的坐標
- (CGPoint)preciseLocationInView:(nullable UIView *)view残黑;
//上一次觸摸的精確的坐標
- (CGPoint)precisePreviousLocationInView:(nullable UIView *)view

//觸摸的力度
CGFloat force;
//觸摸的最大的力度
CGFloat maximumPossibleForce;

//沿著x軸正向的方位角,當與x軸正向方向相同時,該值為0;當view參數(shù)為nil時斋否,
//默認為keyWindow返回觸針的方位角(弧度)。
- (CGFloat)azimuthAngleInView:(nullable UIView *)view NS_AVAILABLE_IOS(9_1);

//當前觸摸對象的方向上的單位向量當view參數(shù)為nil時疫诽,
//默認為keyWindow返回在觸針的方位角的方向指向的單位矢量旦委。
- (CGVector)azimuthUnitVectorInView:(nullable UIView *)view NS_AVAILABLE_IOS(9_1);
//當筆平行于平面時,該值為0
//當筆垂直于平面時,該值為Pi / 2
//觸針的高度(單位為弧度)
CGFloat altitudeAngle ;

//當每個觸摸對象的觸摸特性發(fā)生變化時,
//該值將會單獨增加,返回值是NSNumber 索引號摩钙,
//讓您關聯(lián)與原來的觸摸更新的聯(lián)系
NSNumber * _Nullable estimationUpdateIndex 

//當前觸摸對象估計的觸摸特性,返回值是UITouchPropertyies一組觸摸屬性查辩,
//這些屬性將得到更新
UITouchProperties estimatedProperties 

//一組期望在未來的更新報文的觸摸性能。
UITouchProperties estimatedPropertiesExpectingUpdates;
UITouch對象:

1 當前用戶一根手指觸摸屏幕市 會創(chuàng)建一個與手指相關的UITouch對象 一根手指對應著一個UITouch對象
2如果兩根手指同時觸摸一個view,那么view只會調用一個touchesBegan方法 touches參數(shù)中裝著2個UITouch對象
3如果這兩根手指一前一后分開觸摸同一個view长踊,那么view會分別調用2次touchesBegan 方法并且每次調用的touches參數(shù)只包含一個UITouchd對象

UITouch的作用

1 保存著跟手指有關的信息
2 保存手指的觸摸位置
3 當手指離開屏幕系統(tǒng)會銷毀相應的UITouch對象

筆記三 IOS的事件產生和傳遞

1 事件的觸摸事件的傳遞是從父控件傳遞到子控件 UIApplication -> Window -> 合適的View
2 應用如何找到最合適的控件來處理事件谬返?

1.首先判斷主窗口(keyWindow)自己是否能接受觸摸事件
2.判斷觸摸點是否在自己身上
3.子控件數(shù)組中從后往前遍歷子控件,重復前面的兩個步驟(所謂從后往前遍歷子控件佑刷,就是 首先查找子控件數(shù)組中最后一個元素,然后執(zhí)行1涨冀、2步驟)
4.view麦萤,比如叫做fitView,那么會把這個事件交給這個fitView壮莹,再遍歷這個fitView的子控 件,直至沒有更合適的view為止涝滴。
5.如果沒有符合條件的子控件胶台,那么就認為自己最合適處理這個事件,也就是自己是最合適的view韩脏。

3 UIView不能接收觸摸事件的三種情況:

1 不允許交互:userInteractionEnabled = NO
2 隱藏:如果把父控件隱藏铸磅,那么子控件也會隱藏说订,隱藏的控件不能接受事件
3 透明度:如果設置一個控件的透明度<0.01絮重,會直接影響子控件的透明度霎槐。alpha:0.0~0.01為透明

借用看到的圖片 覺得很清晰的表達了上面的流程:

1055199-48ec84d3d176374e.png

筆記4 如何尋找最合適的view

1 首先判斷主窗口自己能否接受觸摸事件
2 觸摸點是否在自己的身上
3 從后遍歷子控件 重復前面兩個步驟
4 如果沒有符合的子控件就認為自己最合適

筆記5 尋找最合適的view的兩個方法

5.1 hitTest:withEvent:方法

1 什么時候調用丘跌?
只要事件一傳遞給一個控件,這個控件就會調用他自己的hitTest:withEvent方法

2 可以根據這個方法攔截事件

3 特殊情況:
誰都不能處理事件唁桩,窗口也不能處理。

重寫window的hitTest:withEvent:方法return nil
只能有窗口處理事件报辱。

控制器的view的hitTest:withEvent:方法return nil或者window的hitTest:withEvent:方法return self
return nil的含義:
hitTest:withEvent:中return nil的意思是調用當前hitTest:withEvent:方法的view不是合適的view单山,子控件也不是合適的view幅疼。如果同級的兄弟控件也沒有合適的view昼接,那么最合適的view就是父控件。

5.1 pointInside:withEvent:方法

pointInside:withEvent:方法判斷點在不在當前view上(方法調用者的坐標系上)如果返回YES,代表點在方法調用者的坐標系上;返回NO代表點不在方法調用者的坐標系上漂辐,那么方法調用者也就不能處理事件。

筆記6 事件的響應

1事件的響應

1用戶點擊屏幕后產生一個觸摸事件經過一系列的傳遞 會找到最合適的視圖 也就是筆記4和5 為事件的傳遞過程
2 找到合適的視圖后 會通過touch方法將事件順著響應鏈條向上傳遞窘俺,將事件交給上一個響應者處理

2 響應鏈條

響應者鏈條:在iOS程序中無論是最后面的UIWindow還是最前面的某個按鈕复凳,它們的擺放是有前后關系的,一個控件可以放到另一個控件上面或下面对途,那么用戶點擊某個控件時是觸發(fā)上面的控件還是下面的控件呢髓棋,這種先后關系構成一個鏈條就叫“響應者鏈”。也可以說膳犹,響應者鏈是由多個響應者對象連接起來的鏈條签则。在iOS中響應者鏈的關系可以用下圖表示:

1055199-2a49a16e1e483b5c.png
3 響應者對象:能處理事件的對象,也就是繼承自UIResponder的對象
4如何判斷上一個響應者

1> 如果當前這個view是控制器的view,那么控制器就是上一個響應者
2> 如果當前這個view不是控制器的view,那么父控件就是上一個響應者

5 響應鏈的事件傳遞過程

1 如果當前view是控制器的view 那么控制器就是上一個響應者 事件就傳遞給控制器豺旬。如果當前view不是控制器的view 那么父視圖就是當前view的上一個響應者柒凉,事件就會傳遞給它的父視圖

2 在視圖層次結構的最頂級視圖,如果也不能處理的事件或消息 則將其事件或消息傳遞給window對象進行處理

3 如果window對象也不處理 則其講事件或消息傳遞給UIApplication對象

4 如果UIApplication也不能處理就將改事件或消息給丟棄

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{ 
// 默認會把事件傳遞給上一個響應者,上一個響應者是父控件,交給父控件處理
[super touchesBegan:touches withEvent:event]; 
// 注意不是調用父控件的touches方法坦刀,而是調用父類的touches方法
// super是父類 superview是父控件 
}

6事件的傳遞與響應:

1、當一個事件發(fā)生后央渣,事件會從父控件傳給子控件渴频,也就是說由UIApplication -> UIWindow -> UIView -> initial view,以上就是事件的傳遞,也就是尋找最合適的view的過程卜朗。

2场钉、接下來是事件的響應。首先看initial view能否處理這個事件逛万,如果不能則會將事件傳遞給其上級視圖(inital view的superView);如果上級視圖仍然無法處理則會繼續(xù)往上傳遞得封;一直傳遞到視圖控制器view controller指郁,首先判斷視圖控制器的根視圖view是否能處理此事件;如果不能則接著判斷該視圖控制器能否處理此事件疫粥,如果還是不能則繼續(xù)向上傳 遞腰懂;(對于第二個圖視圖控制器本身還在另一個視圖控制器中,則繼續(xù)交給父視圖控制器的根視圖绣溜,如果根視圖不能處理則交給父視圖控制器處理)涮毫;一直到 window贷屎,如果window還是不能處理此事件則繼續(xù)交給application處理,如果最后application還是不能處理此事件則將其丟棄

3唉侄、在事件的響應中,如果某個控件實現(xiàn)了touches...方法恬叹,則這個事件將由該控件來接受,如果調用了[supertouches….];就會將事件順著響應者鏈條往上傳遞唯鸭,傳遞給上一個響應者硅确;接著就會調用上一個響應者的touches….方法

總結:
事件的傳遞是從上到下(父控件到子控件),事件的響應是從下到上(順著響應者鏈條向上傳遞:子控件到父控件菱农。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末循未,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子的妖,更是在濱河造成了極大的恐慌嫂粟,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件忘蟹,死亡現(xiàn)場離奇詭異搁凸,居然都是意外死亡,警方通過查閱死者的電腦和手機护糖,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進店門嫡良,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人坷牛,你說我怎么就攤上這事很澄⊙占埃” “怎么了蹂楣?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長肄扎。 經常有香客問我赁酝,道長,這世上最難降的妖魔是什么雷则? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任肪笋,我火速辦了婚禮,結果婚禮上猜揪,老公的妹妹穿的比我還像新娘坛梁。我一直安慰自己,他們只是感情好划咐,可當我...
    茶點故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布褐缠。 她就那樣靜靜地躺著,像睡著了一般队魏。 火紅的嫁衣襯著肌膚如雪胡桨。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天刽虹,我揣著相機與錄音揽浙,去河邊找鬼意敛。 笑死膛虫,一個胖子當著我的面吹牛钓猬,可吹牛的內容都是我干的。 我是一名探鬼主播敞曹,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼澳迫,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了抓歼?” 一聲冷哼從身側響起拢锹,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蹋半,沒想到半個月后充坑,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡您市,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年役衡,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片榕莺。...
    茶點故事閱讀 40,861評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡棵介,死狀恐怖,靈堂內的尸體忽然破棺而出唠雕,到底是詐尸還是另有隱情,我是刑警寧澤钞脂,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布捕儒,位于F島的核電站,受9級特大地震影響阎毅,放射性物質發(fā)生泄漏点弯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一狼钮、第九天 我趴在偏房一處隱蔽的房頂上張望雌团。 院中可真熱鬧,春花似錦锦援、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至种玛,卻和暖如春瓤檐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背挠蛉。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工谴古, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留质涛,地道東北人。 一個月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓怒炸,卻偏偏與公主長得像瞬测,于是被迫代替她去往敵國和親纠炮。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,860評論 2 361

推薦閱讀更多精彩內容