【问题标题】:How to steal touches from UIScrollView?如何从 UIScrollView 窃取触摸?
【发布时间】:2011-06-05 11:54:13
【问题描述】:

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

感谢您通读整个问题,即使您不知道答案,您仍然可以对问题投赞成票,以便获得更多关注(希望能得到能够回答的人)。谢谢! :)

【问题讨论】:

    标签: iphone ios4 uiscrollview nested uipickerview


    【解决方案1】:

    我也迟到了,但对于新手来说,如果你只是想完全忽略滚动视图上的滑动,对我有用的是在我想忽略的视图中添加一个平移手势识别器滑动,像这样:

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

    【讨论】:

      【解决方案2】:

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

      【讨论】:

      • 最好在答案中包含文章的相关部分,而不是直接链接
      【解决方案3】:

      有时您必须先提出问题才能找到答案。 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

      【讨论】:

      • 既然这仍然是唯一的答案,我会接受它作为我的答案,但如果您有更好的解决方案,请不要犹豫分享!
      • 这是我的首选解决方案。它精益求精,而且很有效。非常感谢!
      • 太好了,为了我的需要我把它改成了([result isKindOfClass:[UITableView class]] || [result.superview isKindOfClass:[UITableView class]] || [result.superview isKindOfClass:[UITableViewCell class]])
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-27
      • 2023-03-06
      • 2013-09-01
      相关资源
      最近更新 更多