iOS觸摸事件

iOS觸摸事件
http://www.reibang.com/p/c294d1bd963d

一.事件的生命周期

1510019-62b6b1eec26730aa.png

系統(tǒng)響應階段

1.手指觸摸屏幕滚停,生成事件由IOKit處理
2.IOKit將事件觸摸封裝為IOHIDEvent事件,通過mach port傳遞給springboard應用(iphone桌面系統(tǒng))
3.SpringBoard進程接收到觸摸事件,觸發(fā)主線程的source1事件源的回調(diào)
根據(jù)桌面狀態(tài)壁肋,判斷誰處理觸摸事件
app未打開硅蹦,SpringBoard處理
app在后臺偏友,通過IPC(進程間通訊)傳遞給app進程

app響應階段

1.app的mach port 接收到SpringBoard進程傳遞的觸摸事件裤翩,主線程runloop被喚醒芥炭,觸發(fā)source1回調(diào)
2.source1回調(diào)觸發(fā)source0回調(diào)享怀,將IOHIDEvent轉(zhuǎn)換為UIEvent羽峰,app正式開始對觸摸事件的響應
3.source0回調(diào)將觸摸事件添加到UIApplication的事件隊列里(先進先出),開始處理的時候,查找最佳響應者梅屉,過程稱為hit-testing
4.找到最佳響應者后(響應鏈確認)值纱,事件在響應鏈中傳遞,事件能被響應者/手勢識別器/target-action捕捉并消耗
5.觸摸事件要么響應后釋放坯汤,要么被丟棄虐唠,runloop若沒有其他事件處理,休眠狀態(tài)

二.觸摸惰聂,事件疆偿,響應者

觸摸UITouch

@property(nonatomic,readonly) NSTimeInterval      timestamp;
@property(nonatomic,readonly) UITouchPhase        phase;
@property(nonatomic,readonly) NSUInteger          tapCount;   // touch down within a certain point within a certain amount of time
@property(nonatomic,readonly) UITouchType         type NS_AVAILABLE_IOS(9_0);
@property(nullable,nonatomic,readonly,strong) UIWindow                        *window;
@property(nullable,nonatomic,readonly,strong) UIView                          *view;
@property(nullable,nonatomic,readonly,copy)   NSArray <UIGestureRecognizer *> *gestureRecognizers NS_AVAILABLE_IOS(3_2);

事件UIEvent

@property(nonatomic,readonly) UIEventType     type NS_AVAILABLE_IOS(3_0);
@property(nonatomic,readonly) UIEventSubtype  subtype NS_AVAILABLE_IOS(3_0);
@property(nonatomic,readonly) NSTimeInterval  timestamp;
#if UIKIT_DEFINE_AS_PROPERTIES
@property(nonatomic, readonly, nullable) NSSet <UITouch *> *allTouches;

響應者UIResponder
所有響應者都為UIResponder對象
UIView/UIViewController/UIApplication/AppDelegate
能響應事件的原因是UIResponder里面的方法

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;
- (void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(nullable UIEvent *)event;

三.hit-testing

尋找最佳響應者的過程

UIApplication->UIWindow->子視圖->子視圖->子視圖
具體流程:

1.UIApplication首先將事件傳遞給窗口對象(UIWindow),若存在多個窗口搓幌,則優(yōu)先詢問后顯示的窗口杆故。
2.若窗口不能響應事件,則將事件傳遞其他窗口溉愁;若窗口能響應事件处铛,則從后往前詢問窗口的子視圖。
3.重復步驟2叉钥。即視圖若不能響應罢缸,則將事件傳遞給上一個同級子視圖;若能響應投队,則從后往前詢問當前視圖的子視圖枫疆。
4.視圖若沒有能響應的子視圖了,則自身就是最合適的響應者敷鸦。

Hit-Testing的本質(zhì)

以下幾種狀態(tài)的視圖無法響應事件:

不允許交互:userInteractionEnabled = NO
隱藏:hidden = YES 如果父視圖隱藏息楔,那么子視圖也會隱藏,隱藏的視圖無法接收事件
透明度:alpha < 0.01 如果設(shè)置一個視圖的透明度<0.01扒披,會直接影響子視圖的透明度值依。alpha:0.0~0.01為透明。

hitTest:withEvent:

每個UIView對象都有一個 hitTest:withEvent: 方法碟案,這個方法是Hit-Testing過程中最核心的存在愿险,其作用是詢問事件在當前視圖中的響應者,同時又是作為事件傳遞的橋梁价说。

hitTest:withEvent: 方法返回一個UIView對象辆亏,作為當前視圖層次中的響應者。默認實現(xiàn)是:

 若當前視圖無法響應事件鳖目,則返回nil
若當前視圖可以響應事件扮叨,但無子視圖可以響應事件,則返回自身作為當前視圖層次中的事件響應者
若當前視圖可以響應事件领迈,同時有子視圖可以響應彻磁,則返回子視圖層次中的事件響應者

一開始UIApplication將事件通過調(diào)用UIWindow對象的 hitTest:withEvent: 傳遞給UIWindow對象碍沐,UIWindow的 hitTest:withEvent: 在執(zhí)行時若判斷本身能響應事件,則調(diào)用子視圖的 hitTest:withEvent: 將事件傳遞給子視圖并詢問子視圖上的最佳響應者衷蜓。最終UIWindow返回一個視圖層次中的響應者視圖給UIApplication累提,這個視圖就是hit-testing的最佳響應者。

四.事件的響應及在響應鏈中的傳遞

經(jīng)歷Hit-Testing后恍箭,UIApplication已經(jīng)知道事件的最佳響應者是誰了刻恭,接下來要做的事情就是:

將事件傳遞給最佳響應者響應
事件沿著響應鏈傳遞
事件響應的前奏
因為最佳響應者具有最高的事件響應優(yōu)先級,因此UIApplication會先將事件傳遞給它供其響應扯夭。首先鳍贾,UIApplication將事件通過 sendEvent: 傳遞給事件所屬的window,window同樣通過 sendEvent: 再將事件傳遞給hit-tested view交洗,即最佳響應者骑科。過程如下:

UIApplication ——> UIWindow ——> hit-tested view

響應者對于事件的操作方式:

響應者對于事件的攔截以及傳遞都是通過 touchesBegan:withEvent: 方法控制的,該方法的默認實現(xiàn)是將事件沿著默認的響應鏈往下傳遞构拳。

響應者對于接收到的事件有3種操作:

不攔截咆爽,默認操作
事件會自動沿著默認的響應鏈往下傳遞
攔截,不再往下分發(fā)事件
重寫 touchesBegan:withEvent: 進行事件處理置森,不調(diào)用父類的 touchesBegan:withEvent:
攔截斗埂,繼續(xù)往下分發(fā)事件
重寫 touchesBegan:withEvent: 進行事件處理,同時調(diào)用父類的 touchesBegan:withEvent: 將事件往下傳遞

參考
http://southpeak.github.io/2015/12/13/cocoa-uikit-uicontrol/
https://developer.apple.com/documentation/uikit/touches_presses_and_gestures/using_responders_and_the_responder_chain_to_handle_events?preferredLanguage=occ#see-also
http://www.reibang.com/p/2e074db792ba

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凫海,一起剝皮案震驚了整個濱河市呛凶,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌行贪,老刑警劉巖漾稀,帶你破解...
    沈念sama閱讀 217,826評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異建瘫,居然都是意外死亡崭捍,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,968評論 3 395
  • 文/潘曉璐 我一進店門啰脚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來殷蛇,“玉大人,你說我怎么就攤上這事橄浓×肋洌” “怎么了?”我有些...
    開封第一講書人閱讀 164,234評論 0 354
  • 文/不壞的土叔 我叫張陵贮配,是天一觀的道長。 經(jīng)常有香客問我塞赂,道長泪勒,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,562評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮圆存,結(jié)果婚禮上叼旋,老公的妹妹穿的比我還像新娘。我一直安慰自己沦辙,他們只是感情好夫植,可當我...
    茶點故事閱讀 67,611評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著油讯,像睡著了一般详民。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上陌兑,一...
    開封第一講書人閱讀 51,482評論 1 302
  • 那天沈跨,我揣著相機與錄音,去河邊找鬼兔综。 笑死饿凛,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的软驰。 我是一名探鬼主播涧窒,決...
    沈念sama閱讀 40,271評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼锭亏!你這毒婦竟也來了纠吴?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,166評論 0 276
  • 序言:老撾萬榮一對情侶失蹤贰镣,失蹤者是張志新(化名)和其女友劉穎呜象,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體碑隆,經(jīng)...
    沈念sama閱讀 45,608評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡恭陡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,814評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了上煤。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片休玩。...
    茶點故事閱讀 39,926評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖劫狠,靈堂內(nèi)的尸體忽然破棺而出拴疤,到底是詐尸還是另有隱情,我是刑警寧澤独泞,帶...
    沈念sama閱讀 35,644評論 5 346
  • 正文 年R本政府宣布呐矾,位于F島的核電站,受9級特大地震影響懦砂,放射性物質(zhì)發(fā)生泄漏蜒犯。R本人自食惡果不足惜组橄,卻給世界環(huán)境...
    茶點故事閱讀 41,249評論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望罚随。 院中可真熱鬧玉工,春花似錦、人聲如沸淘菩。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,866評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽潮改。三九已至狭郑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間进陡,已是汗流浹背愿阐。 一陣腳步聲響...
    開封第一講書人閱讀 32,991評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留趾疚,地道東北人缨历。 一個月前我還...
    沈念sama閱讀 48,063評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像糙麦,于是被迫代替她去往敵國和親辛孵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,871評論 2 354