【code_小馬】解決ScrollView上按鈕攔截響應(yīng)的問題

我們是工程師 ——加油 !

老樣子,先上代碼解燃眉之急,具體思路解釋 見下文

/*UIScrollView高級(jí)用法:
delaysContentTouches與
canCencelContentTouches屬性*/

需求:

UIScrollView+btns。點(diǎn)擊btn高亮(Highlighted),滑動(dòng)UIScrollView時(shí)取消高亮;

分析:

1.實(shí)現(xiàn):點(diǎn)擊btn高亮(Highlighted),且滑動(dòng)UIScrollView時(shí)保持高亮狀態(tài),是不合理的,無法實(shí)現(xiàn)的。(ps還不如直接用cell或者btn的選中狀態(tài))
2.實(shí)現(xiàn):點(diǎn)擊btn高亮(Highlighted), 滑動(dòng)UIScrollView時(shí)取消高亮狀態(tài),是可以做到的。

按照從不同的要素去解釋原理:

一、UIScrollView原理,以時(shí)間為軸線:

從你的手指touch屏幕開始,scrollView開始一個(gè)timer,如果:

  1. 150ms內(nèi)如果你的手指沒有任何動(dòng)作,消息就會(huì)傳給subView。
  2. 150ms內(nèi)手指有明顯的滑動(dòng)(一個(gè)swipe動(dòng)作),scrollView就會(huì)滾動(dòng),消息不會(huì)傳給subView。
  3. 150ms內(nèi)手指沒有滑動(dòng),scrollView將消息傳給subView,但是之后手指開始滑動(dòng),scrollView傳送touchesCancelled消息給subView,然后開始滾動(dòng)。

二、UIScrollView原理,以tracking屬性為軸線:

UIScrollView有一個(gè)BOOL類型的tracking屬性,用來返回用戶是否已經(jīng)觸及內(nèi)容并打算開始滾動(dòng),我們從這個(gè)屬性開始探究UIScrollView的工作原理:

當(dāng)手指觸摸到UIScrollView內(nèi)容的一瞬間,會(huì)有以下動(dòng)作:

  • 攔截觸摸事件
  • tracking屬性變?yōu)閅ES
  • 一個(gè)內(nèi)置的計(jì)時(shí)器開始生效,用來監(jiān)控在極短的事件間隔內(nèi)是否發(fā)生了手指移動(dòng)

case1:當(dāng)檢測(cè)到時(shí)間間隔內(nèi)手指發(fā)生了移動(dòng),UIScrollView自己觸發(fā)滾動(dòng),tracking屬性變?yōu)镹O,手指觸摸下即使有(可以響應(yīng)觸摸事件的)內(nèi)部控件也不會(huì)再響應(yīng)觸摸事件。
case2:當(dāng)檢測(cè)到時(shí)間間隔內(nèi)手指沒有移動(dòng),tracking屬性保持YES,手指觸摸下如果有(可以響應(yīng)觸摸事件的)內(nèi)部控件,則將觸摸事件傳遞給控件進(jìn)行處理。

當(dāng)你手指是緩慢劃過或根本就沒動(dòng),
才會(huì)觸發(fā)UIButton的觸摸事件,這是case1的情況;

有很多新聞?lì)惖腁pp頂部都有一個(gè)滑動(dòng)菜單欄,
主要模型可能是由一個(gè)UIScrollView包含多個(gè)UIButton控件組成;
當(dāng)你操作的時(shí)候,手指如果是很迅速的在上面劃過,
會(huì)發(fā)現(xiàn)即使手指觸摸的地方有UIButton,
但是并沒有觸發(fā)該UIButton的任何觸摸事件,
這就是上面提到的case2。

上面的工作原理其實(shí)有一個(gè)屬性開關(guān)來控制:delaysContentTouches。
解釋:delaysContentTouches
一個(gè)BOOL值,該值決定了滾動(dòng)視圖是否延遲了觸控手勢(shì)的處理。
默認(rèn)值為YES;如果設(shè)置為NO,則無論手指移動(dòng)的多么快,
始終都會(huì)將觸摸事件傳遞給內(nèi)部控件;
設(shè)置為NO可能會(huì)影響到UIScrollView的滾動(dòng)功能。

delaysContentTouches的作用:
這個(gè)標(biāo)志默認(rèn)是YES,使用上面的150ms的timer,
如果設(shè)置為NO,touch事件立即傳遞給subView,
不會(huì)有150ms的等待。

delaysContentTouches :默認(rèn)是YES;如果設(shè)置為NO,會(huì)馬上執(zhí)行touchesShouldBegin:withEvent:inContentView:

- (BOOL)touchesShouldBegin:(NSSet<UITouch *> *)touches
                 withEvent:(UIEvent *)event 
             inContentView:(UIView *)view;


系統(tǒng)默認(rèn)是允許UIScrollView,按照消息響應(yīng)鏈向子視圖傳遞消息的。(即返回YES)
如果你不想U(xiǎn)IScrollView的子視圖接受消息,返回NO。

應(yīng)用描述(本人注釋):這個(gè)方法是最先接收到滑動(dòng)事件的(優(yōu)先于button的
UIControlEventTouchDown,以及
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event),
如果返回YES,touche事件沿著消息響應(yīng)鏈傳遞;
如果返回NO,表示UIScrollView接收這個(gè)滾動(dòng)事件,不必沿著消息響應(yīng)鏈傳遞了。
- (BOOL)touchesShouldCancelInContentView:(UIView *)view
應(yīng)用描述(本人注釋):
如果返回YES:(系統(tǒng)默認(rèn))是允許UIScrollView,按照消息響應(yīng)鏈向子視圖傳遞消息的
如果返回NO:UIScrollView,就接收不到滑動(dòng)事件了。

再看另一個(gè)BOOL類型的屬性canCancelContentTouches,
從字面上理解是“可以取消內(nèi)容觸摸“,默認(rèn)值為YES。
這個(gè)BOOL類型的值控制content view里的觸摸是否總能引發(fā)跟蹤(tracking)
cancelsTouches的作用:
應(yīng)用描述(本人注釋):默認(rèn)設(shè)置為YES,如果設(shè)置為NO,
這消息一旦傳遞給subView,這scroll事件不會(huì)再發(fā)生。

如果屬性值為YES并且跟蹤到手指正觸摸到一個(gè)內(nèi)容控件,這時(shí)如果用戶拖動(dòng)手指的距離足夠產(chǎn)生滾動(dòng),那么內(nèi)容控件將收到一個(gè)touchesCancelled:withEvent:消息,而scroll view將這次觸摸作為滾動(dòng)來處理。如果值為NO,一旦content view開始跟蹤(tracking==YES),則無論手指是否移動(dòng),scrollView都不會(huì)滾動(dòng)。

  • 簡(jiǎn)單點(diǎn)說,如果為YES,就會(huì)等待用戶下一步動(dòng)作,如果用戶移動(dòng)手指到一定距離,就會(huì)把這個(gè)操作作為滾動(dòng)來處理并開始滾動(dòng),同時(shí)發(fā)送一個(gè)touchesCancelled:withEvent:消息給內(nèi)容控件,由控件自行處理。如果為NO,就不會(huì)等待用戶下一步動(dòng)作,并始終不會(huì)觸發(fā)scrollView的滾動(dòng)了。
  • 可以用一段代碼來驗(yàn)證并觀察一下,定義一個(gè)YGScrollView繼承自UIScrollView,一個(gè)YGButton繼承自UIButton,然后重寫部分方法:
//【code_小馬】
YGScrollView.m

- (BOOL)touchesShouldCancelInContentView:(UIView *)view
{
    [super touchesShouldCancelInContentView:view];
    
    NSLog(@"code_小馬:touchesShouldCancelInContentView");
    
    return YES;
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesCancelled:touches withEvent:event];
    
    NSLog(@"code_小馬:touchesCancelled");
}

//【code_小馬】
YGButton.m


- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesCancelled:touches withEvent:event];
    
    NSLog(@"【code_小馬:Button's touch cancelled】");
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesBegan:touches withEvent:event];
    
    NSLog(@"【code_小馬:Button's touch began】");
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesMoved:touches withEvent:event];
    
    NSLog(@"【code_小馬:Button's touch moved】");
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [super touchesEnded:touches withEvent:event];

    NSLog(@"【code_小馬: Button's touch ended】");
}

其實(shí)就是在各個(gè)方法執(zhí)行時(shí)打印出一個(gè)標(biāo)記,

  • 當(dāng)canCencelContentTouches值為YES時(shí),
    用戶觸摸并移動(dòng)手指再放開:輸出臺(tái)

【code_小馬: Button's touch began】
【code_小馬: Button's touch moved】
……
【code_小馬: Button's touch moved】
code_小馬:touchesShouldCancelInContentView
【code_小馬: Button's touch cancelled】

  • 當(dāng)canCencelContentTouches值為NO時(shí),
    用戶觸摸并移動(dòng)手指再放開:輸出臺(tái)

【code_小馬:Button's touch began】
【code_小馬:Button's touch moved】
……
【code_小馬:Button's touch moved】
【code_小馬:Button's touch ended】

【code_小馬】iOS實(shí)用戰(zhàn)術(shù)
本文源碼下載

晌午時(shí)光

  • 很喜歡的一篇文章,拿出來和大家分享
    【第四集】

那天我在巷口看見了如風(fēng)攔住阿福,我剛想走過去卻聽到如風(fēng)說:“別來我家了?!薄  盀槭裁??你姐是街里最漂亮的女孩子!我很中意她!”阿福笑著說?!  皠e來找我姐了。”如風(fēng)說。  “阿風(fēng)啊,你好福氣的!我要是能天天和她睡一間屋,死了也心甘啦……”阿福仍繼續(xù)說著,但他還沒有說完,就被如風(fēng)打倒在了地上?!    澳惘偫?!”阿福怒氣沖沖的爬起來,揮起拳頭就向如風(fēng)打去,轉(zhuǎn)眼間兩個(gè)人就扭打成了一團(tuán)。我驚訝的站在一旁,卻沒想過去拉開他們,因?yàn)槲铱吹诫m然阿福比如風(fēng)高大,但卻是如風(fēng)占了上風(fēng),如風(fēng)打得狠,拼命的狠。還有,就是我想知道,如風(fēng)為什么為了不讓阿福找我而和他打架?! 〔灰粫?huì),阿福就告饒了,如風(fēng)的臉也腫了起來,他不依不饒的說:“別再找我姐,不然我見一次打一次?!卑⒏_B連答應(yīng),戰(zhàn)戰(zhàn)兢兢的走出小巷,看見我居然都沒敢說一句話?!   ∥覜]瞧他一眼就走到如風(fēng)身邊,摸摸他腫脹的臉說:“疼不?”     如風(fēng)搖搖頭,避開我的手?!   ∥矣悬c(diǎn)生氣,討厭他不理我的態(tài)度,板著臉說:“干嗎打阿福?”    他不說話,我更生氣,說:“怪不得虎哥安仔都不來找我了,都是你干的吧!”    如風(fēng)抬起頭,望著我,一字一句的說:“姐,只有我一個(gè)不好嗎?”    他的眼神很純凈,純凈且堅(jiān)定?!   ∥液退麑?duì)望。    只有如風(fēng)一個(gè)人嗎?他雖然不愛說話,但和他在一起卻比和談天說地的阿福在一起舒服,而這種舒服是無處不在的?!   ∷麜?huì)攢了好幾月的錢,買我最愛吃的豆沙餡粽子回來。其實(shí)我從來沒說過自己喜歡豆沙,能有粽子吃還挑選餡料是很奢侈的事情,只是很久以前那次吃粽子,我唯獨(dú)吃了豆沙的兩只,他便默默記下?!   ∷麜?huì)每天在學(xué)校門口等我下學(xué),很自然的拿過我的書包,為我撐傘,踮起腳尖把奶奶給他的圍巾圍在我脖子上?!   ∷麜?huì)在我噘著嘴洗碗時(shí),走到我身邊把我擠開,粗手粗腳的在池子邊干起來。當(dāng)我不小心把盤子摔壞的時(shí)候,會(huì)大聲對(duì)奶奶說:“是我做的!”    我突然發(fā)現(xiàn),原來瘦瘦小小的如風(fēng)一直站在我身邊,當(dāng)虎哥、安仔、阿福都不在時(shí),他永遠(yuǎn)站在那里。而我,很開心他這樣子。    “好,只有你一個(gè)!”我笑著捧著他的臉說,他很害臊似的躲開我的手,但眼神里是說不盡的快樂?!   「羧眨⒏屢姷侥棠踢溃骸澳慵茵B(yǎng)了只狼仔!”奶奶沒說如風(fēng)什么,她總是不說他的,只是時(shí)不時(shí)的搖頭。    此后,再也沒有誰(shuí)來找我了,我也漸漸不再和別人打交道。    那年,我13歲,魏如風(fēng)12歲?!   ∧棠虥]有任何征兆的離開我們了?!   ¢_始她只是有些感冒,不停地咳嗽,我勸她去醫(yī)院但她卻死活不肯:“明日就好了,去花什么錢!你以為那些大夫就醫(yī)得好?還不是騙你白花好些個(gè)!不如多喝些水哩!”    奶奶的明日遲遲不來,末日卻終于臨近。那天傍晚我們放學(xué)回來,奶奶在椅子上已經(jīng)彌留了,她盯著弟弟看了很久,最后看了我一眼,嘆了口氣,沒說一句話睜著眼睛就離開了。我當(dāng)夜哭得死去活來,如風(fēng)一直攥著我的手,片刻不離........................

文章第三集
文章第五集
后續(xù)更新中,喜歡的話 請(qǐng)關(guān)注 ??【code_小馬】?? 哦

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容