(八)解釋栗子

本文系轉(zhuǎn)載锌钮,原文地址為iOS觸摸事件全家桶

現(xiàn)在握爷,把膠卷回放到本章節(jié)開(kāi)頭的場(chǎng)景奴饮。給你一杯咖啡的時(shí)間看看能不能解釋得通那幾個(gè)現(xiàn)象了,不說(shuō)了泡咖啡去了...

我肥來(lái)了迈倍!

先看現(xiàn)象二伤靠,短按 cell無(wú)法響應(yīng),日志如下:

-[GLTableView touchesBegan:withEvent:]
backview taped
-[GLTableView touchesCancelled:withEvent:]

這個(gè)日志和上面離散型手勢(shì)Demo中打印的日志完全一致啼染。短按后宴合,BackView上的手勢(shì)識(shí)別器先接收到事件,之后事件傳遞給hit-tested view迹鹅,作為響應(yīng)者鏈中一員的GLTableView的 touchesBegan:withEvent: 被調(diào)用卦洽;而后手勢(shì)識(shí)別器成功識(shí)別了點(diǎn)擊事件,action執(zhí)行斜棚,同時(shí)通知Application取消響應(yīng)鏈中的事件響應(yīng)阀蒂,GLTableView的 touchesCancelled:withEvent: 被調(diào)用该窗。

因?yàn)槭录蝗∠耍虼薈ell無(wú)法響應(yīng)點(diǎn)擊蚤霞。

再看現(xiàn)象三(長(zhǎng)按Cell)酗失,長(zhǎng)按cell能夠響應(yīng),日志如下:

-[GLTableView touchesBegan:withEvent:]
-[GLTableView touchesEnded:withEvent:]
cell selected!

長(zhǎng)按的過(guò)程中昧绣,一開(kāi)始事件同樣被傳遞給手勢(shì)識(shí)別器和hit-tested view规肴,作為響應(yīng)鏈中一員的GLTableView的 touchesBegan:withEvent: 被調(diào)用;此后在長(zhǎng)按的過(guò)程中夜畴,手勢(shì)識(shí)別器一直在識(shí)別手勢(shì)奏纪,直到一定時(shí)間后手勢(shì)識(shí)別失敗,才將事件的響應(yīng)權(quán)完全交給響應(yīng)鏈斩启。當(dāng)觸摸結(jié)束的時(shí)候序调,GLTableView的 touchesEnded:withEvent: 被調(diào)用,同時(shí)Cell響應(yīng)了點(diǎn)擊兔簇。

OK发绢,現(xiàn)在回到現(xiàn)象一(快速點(diǎn)擊cell)。按照之前的分析垄琐,快速點(diǎn)擊cell边酒,講道理不管是表現(xiàn)還是日志都應(yīng)該和現(xiàn)象二一致才對(duì)。然而日志僅僅打印了手勢(shì)識(shí)別器的action執(zhí)行結(jié)果狸窘。分析一下原因:GLTableView的 touchesBegan 沒(méi)有調(diào)用墩朦,說(shuō)明事件沒(méi)有傳遞給hit-tested view。那只有一種可能翻擒,就是事件被某個(gè)手勢(shì)識(shí)別器攔截了氓涣。目前已知的手勢(shì)識(shí)別器攔截事件的方法,就是設(shè)置 delaysTouchesBegan 為YES陋气,在手勢(shì)識(shí)別器未識(shí)別完成的情況下不會(huì)將事件傳遞給hit-tested view劳吠。然后事實(shí)上并沒(méi)有進(jìn)行這樣的設(shè)置,那么問(wèn)題可能出在別的手勢(shì)識(shí)別器上巩趁。

Window的 sendEvent: 打個(gè)斷點(diǎn)查看event上的touch對(duì)象維護(hù)的手勢(shì)識(shí)別器數(shù)組:

image

捕獲可疑對(duì)象:UIScrollViewDelayedTouchesBeganGestureRecognizer 痒玩,光看名字就覺(jué)得這貨脫不了干系。從類名上猜測(cè)议慰,這個(gè)手勢(shì)識(shí)別器大概會(huì)延遲事件向響應(yīng)鏈的傳遞蠢古。github上找到了該私有類的頭文件

@interface UIScrollViewDelayedTouchesBeganGestureRecognizer : UIGestureRecognizer {
    UIView<UIScrollViewDelayedTouchesBeganGestureRecognizerClient> * _client;
    struct CGPoint { 
        float x; 
        float y; 
    }  _startSceneReferenceLocation;
    UIDelayedAction * _touchDelay;
}
- (void).cxx_destruct;
- (id)_clientView;
- (void)_resetGestureRecognizer;
- (void)clearTimer;
- (void)dealloc;
- (void)sendDelayedTouches;
- (void)sendTouchesShouldBeginForDelayedTouches:(id)arg1;
- (void)sendTouchesShouldBeginForTouches:(id)arg1 withEvent:(id)arg2;
- (void)touchesBegan:(id)arg1 withEvent:(id)arg2;
- (void)touchesCancelled:(id)arg1 withEvent:(id)arg2;
- (void)touchesEnded:(id)arg1 withEvent:(id)arg2;
- (void)touchesMoved:(id)arg1 withEvent:(id)arg2;
@end

有一個(gè)_touchDelay變量,大概是用來(lái)控制延遲事件發(fā)送的别凹。另外草讶,方法列表里有個(gè) sendTouchesShouldBeginForDelayedTouches: 方法,聽(tīng)名字似乎是在一段時(shí)間延遲后向響應(yīng)鏈傳遞事件用的番川。為一探究竟到涂,我創(chuàng)建了一個(gè)類hook了這個(gè)方法:

//TouchEventHook.m
+ (void)load{
    Class aClass = objc_getClass("UIScrollViewDelayedTouchesBeganGestureRecognizer");
    SEL sel = @selector(hook_sendTouchesShouldBeginForDelayedTouches:);
    Method method = class_getClassMethod([self class], sel);
    class_addMethod(aClass, sel, class_getMethodImplementation([self class], sel), method_getTypeEncoding(method));
    exchangeMethod(aClass, @selector(sendTouchesShouldBeginForDelayedTouches:), sel);
}

- (void)hook_sendTouchesShouldBeginForDelayedTouches:(id)arg1{
    [self hook_sendTouchesShouldBeginForDelayedTouches:arg1];
}

void exchangeMethod(Class aClass, SEL oldSEL, SEL newSEL) {
    Method oldMethod = class_getInstanceMethod(aClass, oldSEL);
    Method newMethod = class_getInstanceMethod(aClass, newSEL);
    method_exchangeImplementations(oldMethod, newMethod);
}

斷點(diǎn)看一下點(diǎn)擊cell后 hook_sendTouchesShouldBeginForDelayedTouches: 調(diào)用時(shí)的信息:

image

可以看到這個(gè)手勢(shì)識(shí)別器的 _touchDelay 變量中,保存了一個(gè)計(jì)時(shí)器颁督,以及一個(gè)長(zhǎng)得很像延遲時(shí)間間隔的變量m_delay〖模現(xiàn)在,可以推測(cè)該手勢(shì)識(shí)別器截?cái)嗔耸录⒀舆t0.15s才發(fā)送給hit-tested view沉御。為驗(yàn)證猜測(cè)屿讽,我分別在Window的 sendEvent:hook_sendTouchesShouldBeginForDelayedTouches: 以及TableView的 touchesBegan: 中打印時(shí)間戳吠裆,若猜測(cè)成立伐谈,則應(yīng)當(dāng)前兩者的調(diào)用時(shí)間相差0.15s左右,后兩者的調(diào)用時(shí)間很接近试疙。短按Cell后打印結(jié)果如下(不能快速點(diǎn)擊诵棵,否則還沒(méi)過(guò)延遲時(shí)間觸摸就結(jié)束了,無(wú)法驗(yàn)證猜測(cè)):

-[GLWindow sendEvent:]調(diào)用時(shí)間戳 :
525252194779.07ms
-[TouchEventHook hook_sendTouchesShouldBeginForDelayedTouches:]調(diào)用時(shí)間戳 :
525252194930.91ms
-[TouchEventHook hook_sendTouchesShouldBeginForDelayedTouches:]調(diào)用時(shí)間戳 :
525252194931.24ms
-[GLTableView touchesBegan:withEvent:]調(diào)用時(shí)間戳 :
525252194931.76ms

因?yàn)橛袃蓚€(gè) UIScrollViewDelayedTouchesBeganGestureRecognizer祝旷,所以 hook_sendTouchesShouldBeginForDelayedTouches 調(diào)了兩次履澳,兩次的時(shí)間很接近』初耍可以看到距贷,結(jié)果完全符合猜測(cè)。

這樣就都解釋得通了吻谋。現(xiàn)象一由于點(diǎn)擊后忠蝗,UIScrollViewDelayedTouchesBeganGestureRecognizer 攔截了事件并延遲了0.15s發(fā)送。又因?yàn)辄c(diǎn)擊時(shí)間比0.15s短漓拾,在發(fā)送事件前觸摸就結(jié)束了阁最,因此事件沒(méi)有傳遞到hit-tested view,導(dǎo)致TableView的 touchBegin 沒(méi)有調(diào)用骇两。而現(xiàn)象二闽撤,由于短按的時(shí)間超過(guò)了0.15s,手勢(shì)識(shí)別器攔截了事件并經(jīng)過(guò)0.15s后脯颜,觸摸還未結(jié)束哟旗,于是將事件傳遞給了hit-tested view,使得TableView接收到了事件栋操。因此現(xiàn)象二的日志雖然和離散型手勢(shì)Demo中的日志一致闸餐,但實(shí)際上前者的hit-tested view是在觸摸后延遲了約0.15s左右才接收到觸摸事件的。

至于現(xiàn)象四 矾芙,你現(xiàn)在應(yīng)該已經(jīng)覺(jué)得理所當(dāng)然了才對(duì)舍沙。

(九)結(jié)語(yǔ)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市剔宪,隨后出現(xiàn)的幾起案子拂铡,更是在濱河造成了極大的恐慌壹无,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件感帅,死亡現(xiàn)場(chǎng)離奇詭異斗锭,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)失球,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門岖是,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人实苞,你說(shuō)我怎么就攤上這事豺撑。” “怎么了黔牵?”我有些...
    開(kāi)封第一講書人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵聪轿,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我猾浦,道長(zhǎng)屹电,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任跃巡,我火速辦了婚禮危号,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘素邪。我一直安慰自己外莲,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布兔朦。 她就那樣靜靜地躺著偷线,像睡著了一般。 火紅的嫁衣襯著肌膚如雪沽甥。 梳的紋絲不亂的頭發(fā)上声邦,一...
    開(kāi)封第一講書人閱讀 51,775評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音摆舟,去河邊找鬼亥曹。 笑死,一個(gè)胖子當(dāng)著我的面吹牛恨诱,可吹牛的內(nèi)容都是我干的媳瞪。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼照宝,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼蛇受!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起厕鹃,我...
    開(kāi)封第一講書人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤兢仰,失蹤者是張志新(化名)和其女友劉穎乍丈,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體把将,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡轻专,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了秸弛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡洪碳,死狀恐怖递览,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情瞳腌,我是刑警寧澤绞铃,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站嫂侍,受9級(jí)特大地震影響儿捧,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜挑宠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一菲盾、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧各淀,春花似錦懒鉴、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至奴璃,卻和暖如春悉默,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背苟穆。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工抄课, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人雳旅。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓剖膳,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親岭辣。 傳聞我的和親對(duì)象是個(gè)殘疾皇子吱晒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

推薦閱讀更多精彩內(nèi)容

  • 在iOS開(kāi)發(fā)中經(jīng)常會(huì)涉及到觸摸事件。本想自己總結(jié)一下沦童,但是遇到了這篇文章仑濒,感覺(jué)總結(jié)的已經(jīng)很到位叹话,特此轉(zhuǎn)載。作者:L...
    WQ_UESTC閱讀 6,013評(píng)論 4 26
  • 本文主要講解iOS觸摸事件的一系列機(jī)制墩瞳,涉及的問(wèn)題大致包括: 觸摸事件由觸屏生成后如何傳遞到當(dāng)前應(yīng)用驼壶? 應(yīng)用接收觸...
    baihualinxin閱讀 1,210評(píng)論 0 9
  • 轉(zhuǎn)載: https://blog.csdn.net/qq871531334/article/details/822...
    NicooYang閱讀 1,591評(píng)論 0 9
  • 觸摸事件的生命周期 當(dāng)我們手指觸碰屏幕的那一刻热凹,一個(gè)觸摸事件便產(chǎn)生了。經(jīng)過(guò)進(jìn)程間通信泪电,觸摸事件被傳遞到合適的應(yīng)用之...
    Gintok閱讀 1,356評(píng)論 0 3
  • 在開(kāi)發(fā)過(guò)程中般妙,大家或多或少的都會(huì)碰到令人頭疼的手勢(shì)沖突問(wèn)題,正好前兩天碰到一個(gè)類似的bug相速,于是借著這個(gè)機(jī)會(huì)了解了...
    閆仕偉閱讀 5,339評(píng)論 2 23