我尝试的第一件事是覆盖重写。
- (BOOL)touchesShouldCancelInContentView:(UIView *)view
可以简单地禁止UIScrollView在选择器视图内取消触摸事件。这样做是可行的,但有一个不愉快的副作用。你希望选择器视图能够立即响应,因此必须将delaysContentTouches
设置为NO。问题在于,你不希望其余的表格视图也立即响应,因为如果这样做,表格视图单元格将始终在滚动开始前高亮显示几毫秒。
我尝试的第二件事是覆盖重写
- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
因为我曾经读过滚动视图总是会返回自己,从而会“窃取”其子视图的触摸事件,如果这些事件对于滚动视图不重要,它将稍后将它们发送给子视图。然而,这种说法已经不再正确。UIScrollView的默认hitTest:withEvent: 实现实际上会返回应该接收触摸事件的子视图。相反,它使用手势识别器来拦截触摸事件。
所以我尝试的第三件事情是实现自己的手势识别器,并在触摸事件在选择器视图之外时使其失败,在选择器视图内时使其成功。然后,我使用以下代码将所有滚动视图的手势识别器设置为只有当我的手势识别器失败时才失败:
for (UIGestureRecognizer * gestureRecognizer in self.tableView.gestureRecognizers)
{
[gestureRecognizer requireGestureRecognizerToFail:myRecognizer];
}
实际上,这确实从滚动视图中窃取了触摸事件,但选择器视图却从未收到它们。因此,我想也许我可以使用以下代码将手势识别器接收到的所有触摸事件发送出去:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
for (UITouch *touch in touches)
[touch.view touchesBegan:touches withEvent:event];
}
以上代码是一个简化版。我还确保视图是选择器视图(或其子视图之一),并像我上面提到的那样设置手势识别器的适当状态。我同样对于取消、结束和移动时也做了相同的处理。然而,选择器视图仍然没有响应。
在回到我的正常工作之前,我还尝试了最后一件事情。在广泛搜索后,我读到嵌套的UIScrollViews自3.x开始就可以神奇地工作,因此我将我的选择器视图放在了嵌套的UIScrollView中,并在其上设置了以下属性:
scrollView.delaysContentTouches = NO;
scrollView.canCancelContentTouches = NO;
如预期所料,外部滚动视图对待内部滚动视图与对待选择器视图一样,导致内部滚动视图无法接收到触摸事件。我知道UIScrollView具有名为UIScrollViewDelayedTouchesBeganGestureRecognizer
的手势识别器,该手势识别器会在150(?)毫秒后拦截触摸事件,并将其发送到适当的子视图。我认为我应该能够编写类似的手势识别器,使滚动视图的默认识别器失败,并立即将触摸事件发送到选择器视图。如果有人知道如何编写这样的手势识别器,请告诉我,如果您有其他解决问题的方法,也可以分享一下。感谢您阅读整个问题,即使您不知道答案,也可以给问题点赞,以便它得到更多关注(希望来自能够回答的人)。谢谢! :)
([result isKindOfClass:[UITableView class]] || [result.superview isKindOfClass:[UITableView class]] || [result.superview isKindOfClass:[UITableViewCell class]])
。 - Diziet