如何从UIScrollView窃取触摸?

时间:2011-01-07 19:33:59

标签: iphone ios4 uiscrollview nested uipickerview

今天,在我的创作时间,我做了一些非常全面的研究,如何从UIScrollView窃取触摸并立即将它们发送到特定的子视图,同时保持其余滚动视图的默认行为。考虑在UITableView中使用UIPickerView。默认行为是,如果您将手指拖到选择器视图上,滚动视图将滚动,选择器视图将保持不变。

我尝试的第一件事就是覆盖

- (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(?)ms后将它们发送到适当的子视图。我想我应该能够写一个类似的识别器,导致滚动视图的默认识别器失败,而不是延迟触摸立即将它们发送到选择器视图。因此,如果有人知道如何编写这样的识别器,请告诉我,如果您有任何其他问题的解决方案,那么您也非常欢迎分享。

感谢您阅读整个问题,即使您不知道答案,您仍然可以提出问题,以便得到更多关注(希望能得到答案的人)。谢谢! :)

3 个答案:

答案 0 :(得分:35)

有时你必须先问问题才能找到答案。 Dan Ray遇到了类似的问题,并用一种​​非常不同的解决方案解决了这个问题。

- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView* result = [super hitTest:point withEvent:event];

    if ([result.superview isKindOfClass:[UIPickerView class]])
    {
        self.scrollEnabled = NO;
    }
    else 
    {
        self.scrollEnabled = YES;    
    }
    return result;
}

我已经测试了代码,它也适用于我。然而,这并不是真正从滚动视图中偷取的东西,所以如果有人知道如何实际窃取那些很棒的触摸。

来源: UIPickerView inside UITableView.tableFooterView doesn't receive drag touches

答案 1 :(得分:4)

有点晚了,但我找到了这个解决方案: http://www.cocoanetics.com/2010/06/hacking-uiscrollview-gesture-recognizers/ 适合我

答案 2 :(得分:0)

我也参加聚会很晚,但是对于新手来说,如果您只是想平移滚动视图上的忽略滑动,对我有用的是在我要忽略的视图中添加平移手势识别器滑动,就像这样:

let panGesture = UIPanGestureRecognizer()
panGesture.cancelsTouchesInView = false
myView?.addGestureRecognizer(panGesture)