老樣子,先上代碼解燃眉之急,具體思路解釋 見下文
- 開源代碼在github上直接下載
下載鏈接: https://github.com/McodeYG/-code_-ScrollView-Btn
/*UIScrollView高級用法:
delaysContentTouches與
canCencelContentTouches屬性*/
需求:
UIScrollView+btns。點擊btn高亮(Highlighted),滑動UIScrollView時取消高亮;
分析:
1.實現:點擊btn高亮(Highlighted),且滑動UIScrollView時保持高亮狀態,是不合理的,無法實現的。(ps還不如直接用cell或者btn的選中狀態)
2.實現:點擊btn高亮(Highlighted), 滑動UIScrollView時取消高亮狀態,是可以做到的。
按照從不同的要素去解釋原理:
一、UIScrollView原理,以時間為軸線:
從你的手指touch屏幕開始,scrollView開始一個timer,如果:
- 150ms內如果你的手指沒有任何動作,消息就會傳給subView。
- 150ms內手指有明顯的滑動(一個swipe動作),scrollView就會滾動,消息不會傳給subView。
- 150ms內手指沒有滑動,scrollView將消息傳給subView,但是之后手指開始滑動,scrollView傳送touchesCancelled消息給subView,然后開始滾動。
二、UIScrollView原理,以tracking屬性為軸線:
UIScrollView有一個BOOL類型的tracking屬性,用來返回用戶是否已經觸及內容并打算開始滾動,我們從這個屬性開始探究UIScrollView的工作原理:
當手指觸摸到UIScrollView內容的一瞬間,會有以下動作:
- 攔截觸摸事件
- tracking屬性變為YES
- 一個內置的計時器開始生效,用來監控在極短的事件間隔內是否發生了手指移動
case1:當檢測到時間間隔內手指發生了移動,UIScrollView自己觸發滾動,tracking屬性變為NO,手指觸摸下即使有(可以響應觸摸事件的)內部控件也不會再響應觸摸事件。
case2:當檢測到時間間隔內手指沒有移動,tracking屬性保持YES,手指觸摸下如果有(可以響應觸摸事件的)內部控件,則將觸摸事件傳遞給控件進行處理。
當你手指是緩慢劃過或根本就沒動,
才會觸發UIButton的觸摸事件,這是case1的情況;
有很多新聞類的App頂部都有一個滑動菜單欄,
主要模型可能是由一個UIScrollView包含多個UIButton控件組成;
當你操作的時候,手指如果是很迅速的在上面劃過,
會發現即使手指觸摸的地方有UIButton,
但是并沒有觸發該UIButton的任何觸摸事件,
這就是上面提到的case2。
上面的工作原理其實有一個屬性開關來控制:delaysContentTouches。
解釋:delaysContentTouches
一個BOOL值,該值決定了滾動視圖是否延遲了觸控手勢的處理。
默認值為YES;如果設置為NO,則無論手指移動的多么快,
始終都會將觸摸事件傳遞給內部控件;
設置為NO可能會影響到UIScrollView的滾動功能。
delaysContentTouches的作用:
這個標志默認是YES,使用上面的150ms的timer,
如果設置為NO,touch事件立即傳遞給subView,
不會有150ms的等待。
delaysContentTouches :默認是YES;如果設置為NO,會馬上執行touchesShouldBegin:withEvent:inContentView:
- (BOOL)touchesShouldBegin:(NSSet<UITouch *> *)touches
withEvent:(UIEvent *)event
inContentView:(UIView *)view;
系統默認是允許UIScrollView,按照消息響應鏈向子視圖傳遞消息的。(即返回YES)
如果你不想UIScrollView的子視圖接受消息,返回NO。
應用描述(本人注釋):這個方法是最先接收到滑動事件的(優先于button的
UIControlEventTouchDown,以及
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event),
如果返回YES,touche事件沿著消息響應鏈傳遞;
如果返回NO,表示UIScrollView接收這個滾動事件,不必沿著消息響應鏈傳遞了。
- (BOOL)touchesShouldCancelInContentView:(UIView *)view
應用描述(本人注釋):
如果返回YES:(系統默認)是允許UIScrollView,按照消息響應鏈向子視圖傳遞消息的
如果返回NO:UIScrollView,就接收不到滑動事件了。
再看另一個BOOL類型的屬性canCancelContentTouches,
從字面上理解是“可以取消內容觸摸“,默認值為YES。
這個BOOL類型的值控制content view里的觸摸是否總能引發跟蹤(tracking)
cancelsTouches的作用:
應用描述(本人注釋):默認設置為YES,如果設置為NO,
這消息一旦傳遞給subView,這scroll事件不會再發生。
如果屬性值為YES并且跟蹤到手指正觸摸到一個內容控件,這時如果用戶拖動手指的距離足夠產生滾動,那么內容控件將收到一個touchesCancelled:withEvent:消息,而scroll view將這次觸摸作為滾動來處理。如果值為NO,一旦content view開始跟蹤(tracking==YES),則無論手指是否移動,scrollView都不會滾動。
- 簡單點說,如果為YES,就會等待用戶下一步動作,如果用戶移動手指到一定距離,就會把這個操作作為滾動來處理并開始滾動,同時發送一個touchesCancelled:withEvent:消息給內容控件,由控件自行處理。如果為NO,就不會等待用戶下一步動作,并始終不會觸發scrollView的滾動了。
- 可以用一段代碼來驗證并觀察一下,定義一個YGScrollView繼承自UIScrollView,一個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】");
}
其實就是在各個方法執行時打印出一個標記,
- 當canCencelContentTouches值為YES時,
用戶觸摸并移動手指再放開:輸出臺
【code_小馬: Button's touch began】
【code_小馬: Button's touch moved】
……
【code_小馬: Button's touch moved】
code_小馬:touchesShouldCancelInContentView
【code_小馬: Button's touch cancelled】
- 當canCencelContentTouches值為NO時,
用戶觸摸并移動手指再放開:輸出臺
【code_小馬:Button's touch began】
【code_小馬:Button's touch moved】
……
【code_小馬:Button's touch moved】
【code_小馬:Button's touch ended】
【code_小馬】iOS實用戰術
本文源碼下載
晌午時光
- 很喜歡的一篇文章,拿出來和大家分享
【第四集】
那天我在巷口看見了如風攔住阿福,我剛想走過去卻聽到如風說:“別來我家了?!薄 盀槭裁??你姐是街里最漂亮的女孩子!我很中意她!”阿福笑著說。 “別來找我姐了?!比顼L說?! 鞍L啊,你好福氣的!我要是能天天和她睡一間屋,死了也心甘啦……”阿福仍繼續說著,但他還沒有說完,就被如風打倒在了地上。 “你瘋啦!”阿福怒氣沖沖的爬起來,揮起拳頭就向如風打去,轉眼間兩個人就扭打成了一團。我驚訝的站在一旁,卻沒想過去拉開他們,因為我看到雖然阿福比如風高大,但卻是如風占了上風,如風打得狠,拼命的狠。還有,就是我想知道,如風為什么為了不讓阿福找我而和他打架?! 〔灰粫⒏>透骛埩耍顼L的臉也腫了起來,他不依不饒的說:“別再找我姐,不然我見一次打一次?!卑⒏_B連答應,戰戰兢兢的走出小巷,看見我居然都沒敢說一句話?! ∥覜]瞧他一眼就走到如風身邊,摸摸他腫脹的臉說:“疼不?” 如風搖搖頭,避開我的手?! ∥矣悬c生氣,討厭他不理我的態度,板著臉說:“干嗎打阿福?” 他不說話,我更生氣,說:“怪不得虎哥安仔都不來找我了,都是你干的吧!” 如風抬起頭,望著我,一字一句的說:“姐,只有我一個不好嗎?” 他的眼神很純凈,純凈且堅定?! ∥液退麑ν! ≈挥腥顼L一個人嗎?他雖然不愛說話,但和他在一起卻比和談天說地的阿福在一起舒服,而這種舒服是無處不在的?! ∷麜€了好幾月的錢,買我最愛吃的豆沙餡粽子回來。其實我從來沒說過自己喜歡豆沙,能有粽子吃還挑選餡料是很奢侈的事情,只是很久以前那次吃粽子,我唯獨吃了豆沙的兩只,他便默默記下?! ∷麜刻煸趯W校門口等我下學,很自然的拿過我的書包,為我撐傘,踮起腳尖把奶奶給他的圍巾圍在我脖子上。 他會在我噘著嘴洗碗時,走到我身邊把我擠開,粗手粗腳的在池子邊干起來。當我不小心把盤子摔壞的時候,會大聲對奶奶說:“是我做的!” 我突然發現,原來瘦瘦小小的如風一直站在我身邊,當虎哥、安仔、阿福都不在時,他永遠站在那里。而我,很開心他這樣子。 “好,只有你一個!”我笑著捧著他的臉說,他很害臊似的躲開我的手,但眼神里是說不盡的快樂?! 「羧眨⒏屢姷侥棠踢溃骸澳慵茵B了只狼仔!”奶奶沒說如風什么,她總是不說他的,只是時不時的搖頭。 此后,再也沒有誰來找我了,我也漸漸不再和別人打交道?! ∧悄?,我13歲,魏如風12歲?! ∧棠虥]有任何征兆的離開我們了。 開始她只是有些感冒,不停地咳嗽,我勸她去醫院但她卻死活不肯:“明日就好了,去花什么錢!你以為那些大夫就醫得好?還不是騙你白花好些個!不如多喝些水哩!” 奶奶的明日遲遲不來,末日卻終于臨近。那天傍晚我們放學回來,奶奶在椅子上已經彌留了,她盯著弟弟看了很久,最后看了我一眼,嘆了口氣,沒說一句話睜著眼睛就離開了。我當夜哭得死去活來,如風一直攥著我的手,片刻不離........................