老样子,先上代码解燃眉之急,具体思路解释 见下文
- 开源代码在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实用战术
本文源码下载
晌午时光
- 很喜欢的一篇文章,拿出来和大家分享
【第四集】
那天我在巷口看见了如风拦住阿福,我刚想走过去却听到如风说:“别来我家了。” “为什么?你姐是街里最漂亮的女孩子!我很中意她!”阿福笑着说。 “别来找我姐了。”如风说。 “阿风啊,你好福气的!我要是能天天和她睡一间屋,死了也心甘啦……”阿福仍继续说着,但他还没有说完,就被如风打倒在了地上。 “你疯啦!”阿福怒气冲冲的爬起来,挥起拳头就向如风打去,转眼间两个人就扭打成了一团。我惊讶的站在一旁,却没想过去拉开他们,因为我看到虽然阿福比如风高大,但却是如风占了上风,如风打得狠,拼命的狠。还有,就是我想知道,如风为什么为了不让阿福找我而和他打架。 不一会,阿福就告饶了,如风的脸也肿了起来,他不依不饶的说:“别再找我姐,不然我见一次打一次。”阿福连连答应,战战兢兢的走出小巷,看见我居然都没敢说一句话。 我没瞧他一眼就走到如风身边,摸摸他肿胀的脸说:“疼不?” 如风摇摇头,避开我的手。 我有点生气,讨厌他不理我的态度,板着脸说:“干吗打阿福?” 他不说话,我更生气,说:“怪不得虎哥安仔都不来找我了,都是你干的吧!” 如风抬起头,望着我,一字一句的说:“姐,只有我一个不好吗?” 他的眼神很纯净,纯净且坚定。 我和他对望。 只有如风一个人吗?他虽然不爱说话,但和他在一起却比和谈天说地的阿福在一起舒服,而这种舒服是无处不在的。 他会攒了好几月的钱,买我最爱吃的豆沙馅粽子回来。其实我从来没说过自己喜欢豆沙,能有粽子吃还挑选馅料是很奢侈的事情,只是很久以前那次吃粽子,我唯独吃了豆沙的两只,他便默默记下。 他会每天在学校门口等我下学,很自然的拿过我的书包,为我撑伞,踮起脚尖把奶奶给他的围巾围在我脖子上。 他会在我噘着嘴洗碗时,走到我身边把我挤开,粗手粗脚的在池子边干起来。当我不小心把盘子摔坏的时候,会大声对奶奶说:“是我做的!” 我突然发现,原来瘦瘦小小的如风一直站在我身边,当虎哥、安仔、阿福都不在时,他永远站在那里。而我,很开心他这样子。 “好,只有你一个!”我笑着捧着他的脸说,他很害臊似的躲开我的手,但眼神里是说不尽的快乐。 隔日,阿福妈见到奶奶啐道:“你家养了只狼仔!”奶奶没说如风什么,她总是不说他的,只是时不时的摇头。 此后,再也没有谁来找我了,我也渐渐不再和别人打交道。 那年,我13岁,魏如风12岁。 奶奶没有任何征兆的离开我们了。 开始她只是有些感冒,不停地咳嗽,我劝她去医院但她却死活不肯:“明日就好了,去花什么钱!你以为那些大夫就医得好?还不是骗你白花好些个!不如多喝些水哩!” 奶奶的明日迟迟不来,末日却终于临近。那天傍晚我们放学回来,奶奶在椅子上已经弥留了,她盯着弟弟看了很久,最后看了我一眼,叹了口气,没说一句话睁着眼睛就离开了。我当夜哭得死去活来,如风一直攥着我的手,片刻不离........................