忽略触摸拖动事件并传递给UIScrollView的UIButton

10

我知道Stack上有类似的帖子,但我没有找到任何能帮助我找到解决方案的东西。

  • 我在一个UIView中添加了一个scrollview
  • 我在同一个UIView上方的scrollview中添加了一个UIButton

    1. 我希望UIButton响应touchUp并触发事件。
    2. 如果有人在UIButton上拖动,我希望它将事件传递给scrollView,拖动UIScrollView而不触发按钮事件。

我知道如何通过hitTest传递触摸到scrollview,但这会阻止按钮接收任何事件。

不想将UIButton添加到UIScrollView中。

有人有提议的解决方案吗?


关于这个旧问题。如果您有一个滚动视图的子视图X,将X具有附加到整体视图而不是滚动视图的约束完全没有问题!非常简单,X就不会滚动。它只是停留在顶部。就是这么简单! - Fattie
只是为了重申一下这个解释:假设按钮B是滚动视图S的子视图,而滚动视图则位于一个整体视图V中。令人惊讶的是,B确实需要滚动。但是请注意,B并不需要滚动。只需将B附加到V(而不是S),问题就解决了。事实上,就是这么简单。 - Fattie
因此,正如Morgz所述的那样,仅需在第2点中将按钮设置为滚动视图的子视图,但出人意料地将按钮约束到整个UIView即可!这很容易。 - Fattie
4个回答

2
尝试这样做:子类化UIScrollView,在touchesShouldCancelInContentView:方法中返回YES。

1
为我工作!非常感谢!:] - Jerome
我认为这不正确?请注意,在问题中,按钮在滚动条的上方,而不是反过来。 - Fattie

1

正如这个答案中所解释的那样,作为滚动视图子视图的UIButton或其他UIControl将自动响应点击事件而让滚动视图处理拖动事件。但是,作为滚动视图子视图的按钮也会随着滚动内容移动,而不是在内容滚动时保持在屏幕上的同一位置。我猜这就是为什么您不想将按钮放入滚动视图的原因。

如果是这种情况,您可以通过以下步骤获得所需的行为。将所有按钮放入一个UIView中,该UIView是滚动视图的子视图,然后在滚动视图的委托方法scrollViewDidScroll中,将该视图的frame.origin设置为滚动视图的contentOffset。我刚刚在我的应用程序中实现了这一点,并且它运行得很好,无需进行任何子类化或与响应者链或触摸事件有关的操作。


这里的第一个段落完全正确。但第二个段落并不必要!将子视图约束到滚动视图的超级视图中完全没问题!简单地说,子视图将不会滚动,它只是停留在顶部。就是这么简单! - Fattie
@Fattie 请注意,当这个问题及其答案被撰写时,自动布局并不存在。但是,使用当前的编码工具发布一个新的答案会很好。 - arlomedia
太棒了,@arlomedia 的观点非常好!是的,确实旧的SO QA正在成为一个问题。我的许多最早的答案现在完全过时了,并且涉及不存在的技术。 - Fattie
@Fattie 幸运的是,所有的内容都有明确的日期,所以我在浏览帖子时总是记住它们的发布时间。 - arlomedia

1
尝试为UIButton添加UIPanGestureRecognizer。在处理拖动的回调函数中,您无需实现任何内容。然后,将cancelsTouchesInView设置为YES。这将导致您的按钮将拖动手势传递给其他视图。
并且这是handlePan:
我遇到了类似的情况,其中我有一个UIScrollView和两个UIView子视图。每个UIView都包含一个UISlider。我想捕捉(和放置)垂直拖动(这就是手势识别器派上用场的地方),但我也需要水平滚动以按预期方式在滑块中工作,并使滚动视图左右移动。这是解决方案。(手势识别器附加到每个UIView。)

虽然我的设置略有不同,但这对我没有用。与scrollView不同,我只是在一个viewController上有几个可以拖动的视图。我的问题是,其中一些子视图有按钮(因为它们会响应点击),而这些按钮会阻止拖动行为。我本以为这个答案会解决它,但是,唉,没有。任何额外的提示都将不胜感激。谢谢! - Olie
为了澄清,我还尝试将 gr 复制到包含按钮的较小子视图上,希望将 pan 传递到其父视图。但是没有成功。 - Olie

1

尝试这个:

  1. 在滚动视图上添加一个透明的自定义UIView,大小与整个滚动视图的contentSize相同,覆盖所有其他视图。(或者,将其设置为与滚动视图的宽度/高度一样大,并在每次滚动视图移动时简单地移动它。)当滚动视图决定将其触摸传递给其子视图而不是拖动时,这将是第一个被hitTested的东西。
  2. 重写UIView的hitTest方法。检查触摸是否在您的按钮框架内。如果是,则返回按钮;否则返回nil。

实际上,您会欺骗滚动视图,使其认为按钮是其子视图之一。我不确定这是否有效,因为我实际上还没有尝试过,但它似乎完全合理。


我尝试过这个,但是无法使其工作。问题在于hitTest方法会在你滑动滚动视图或仅仅是点击它时被调用,所以自定义的hitTest方法不知道是否将事件传递到滚动视图,还是重定向到按钮。我还尝试在自定义视图中使用touchesMoved来计算它是否接收到触摸或点击,但是当调用touchesMove时,hitTest方法已经完成了,因此没有办法在那里有条件地响应。 - arlomedia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接