前言
为什么我会注意到这两个属性呢,因为当初在做一个可编辑的表单时,遇到使用touch方式处理键盘收起但是没效果的情况,具体解决办法请看UITableView键盘隐藏 。
简述
delaysContentTouches和canCancelContentTouches都是scrollView的一个属性,在讲这两个属性之前,首先要讲下scrollView的一个机制。
从你的手指touch屏幕开始,scrollView开始一个timer,如果:
- 150ms内如果你的手指没有任何动作,消息就会传给subView。
- 150ms内手指有明显的滑动(一个swipe动作),scrollView就会滚动,消息不会传给subView。
- 150ms内手指没有滑动,scrollView将消息传给subView,但是之后手指开始滑动,scrollView传送touchesCancelled消息给subView,然后开始滚动。
delaysContentTouches:默认值为YES。如果设置为NO,则会立即把事件传递给subView。
canCancelContentTouches:默认为YES,如果设置为NO,这消息一旦传递给subView,这scroll事件不会再发生。
实践
在storyboard拉入一个scrollView,然后在scrollView里面拉一个view,这个view是自定义的view,实现如下方法
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"摸到了");
}
-(void)touchesCancelled:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
NSLog(@"不摸了");
}
storyboard张这样

情形一:delaysContentTouches和canCancelContentTouches都为YES(即默认情况)

上图显示
第一次,点击中间的view之后,先停顿一会,之后再开始拖拽(下同)。停顿时scrollView把事件传递给view,view响应了touchesBegan事件。之后开始拖拽,这时view收到了touchesCancelled事件,然后开始滚动了。
第二次,点击中间的view之后,直接开始拖拽(下同)。因为中间没有停顿,所以view没有接收到任何事件。
情形二:delaysContentTouches为NO和canCancelContentTouches为YES

上图显示
第二次,虽然点击后直接开始拖拽,但是因为scrollView把事件传递给subView是没有延迟的,所以view就立马接收到touchesBegan事件,拖动的那一瞬间,view又接收到touchesCancelled事件。
那第一次,就不用说了。
情形三:delaysContentTouches为YES和canCancelContentTouches为NO

第一次,停顿时scrollView把事件传递给view,view响应了touchesBegan事件,所以控制台打出了“摸到了”。之后开始滚动,但是view不会接收touchesCancelled事件,而是阻止了scrollView的滚动。
第二次,因为中间没有停顿,所以view压根没接收到touch事件,所以也没法阻止scrollView的滚动。
情形四:delaysContentTouches和canCancelContentTouches都为NO

第二次,虽然点击后直接开始拖拽,但是因为scrollView把事件传递给subView是没有延迟的,所以view就立马接收到touchesBegan事件。之后开始拖曳,但是view不会接收touchesCancelled事件,而是阻止了scrollView的滚动。
第一次,也不用说了。
至此,这两个属性的用处大家应该都清楚了吧。
切记
千万不要在tableView上试delaysContentTouches属性,那会让你试到怀疑人生的。这个属性在tableView上根本没有效果。这点我也没找到原因,还是在我同事的提醒下,我才意识到这点。
如果本文让你有那么点觉得“I get”的感觉,请点个赞呗!写作很辛苦,路过请点赞!
网友评论
@Implementation ResponseTableView
- (instancetype) initWithCoder : (NSCoder *) aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
self.delaysContentTouches = NO;
//因为 UITableViewWrapperView 在iOS7不属于UIScrollView
//iOS7
for (id obj in self.subviews) {
if ([NSStringFromClass([obj class]) isEqualToString:@"UITableViewCellScrollView"]) {
UIScrollView *scrollView = (UIScrollView *) obj;
scrollView.delaysContentTouches = NO;
break;
}
}
//ios 8
for (id view in self.subviews) {
if ([NSStringFromClass([view class]) isEqualToString:@"UITableViewWrapperView"]) {
if ([view isKindOfClass:[UIScrollView class]]) {
UIScrollView *scrollView = (UIScrollView *) view;
scrollView.delaysContentTouches = NO;
}
break;
}
}
}
return self;
}
- (BOOL) touchesShouldCancelInContentView : (UIView *) view {
if ([view isKindOfClass:[UIButton class]]) {
return YES;
}
return [super touchesShouldCancelInContentView:view];
}