【问题标题】:Handle tap event by subview of UIScrollView while scrolling滚动时通过 UIScrollView 的子视图处理点击事件
【发布时间】:2012-07-22 17:04:03
【问题描述】:

我有自定义 UIScrollView 子类,里面有一些内容视图。其中一些我有 UITapGestureRecognizer。当滚动视图不滚动时,一切正常。但是当它滚动内容视图时不会收到点击动作。在滚动视图滚动时通过子视图处理点击操作的最简单解决方案是什么?

详情:

MyScrollView 水平滚动。它包含很多内容视图(例如MyContentView)。每个MyContentView 的宽度约为MyScrollView 宽度的三分之一。所以现在大约有 3-4 个可见的 MyContentView 元素。 MyScrollView 的主要行为是 1)确保滚动后 MyContentView 元素之一将位于屏幕中心,2)如果用户点击它,滚动到 MyContentView 的中心。所以我希望得到的主要答案是如何在MyContentView 减速时“正确”实现对点击动作的处理。

我发现了一些相同的问题和答案,但没有一个让我满意。最好的方法是实现 UITapGestureRecogniser 委托的gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:。但在这种情况下,我有时(当我点击时,让 smaaaal 拖动并释放手指,所以点击是钢可识别的(我们称之为准点击))同时有点击和滚动事件,这对我来说会导致错误即使我开始点击时滚动视图没有滚动。当用户准点击时,我的应用程序尝试滚动到点击的MyContentView 元素,然后立即处理正常滚动。这似乎更可怕,因为在处理点击后开始执行一些其他功能(在正常滚动时它不能执行)。

我需要滚动视图等待足以确定它不是点击事件然后才进行滚动的解决方案。否则,如果点击事件已识别滚动,则不得发生。

【问题讨论】:

  • 您能否更具体地说明它导致您遇到的错误?请描述预期结果和观察到的结果,以便我们找出行为不端的原因。
  • 我已经按照你的要求编辑了我的问题。
  • 很快,就没有办法了。UIScrollView 自身位置发生重大变化之前,您的UIScrollView 子视图无法接收来自用户的任何交互。移动完成后,UIScrollView 将点击事件传递给它自己的子视图,然后你可以捕捉它们。请找到更多信息here

标签: objective-c ios cocoa-touch uiscrollview uigesturerecognizer


【解决方案1】:

这是 UIScrollView 内置的 - 查看 delaysContentTouchescanCancelContentTouches 属性。这应该可以缓解点击后拖动一点点时的问题。

这是所有系统内置行为。我建议坚持使用 Apple 为您的界面提供的感觉(例如,它对小阻力的反应),这样您的应用程序就不会在用户的手机上感觉格格不入。

编辑:

或者,您可以在手势识别器中禁用滚动视图的滚动,并在结束/取消后重新启用它。

进一步编辑: 我不明白 - 我创建了一个sample project,它说明了如何使用手势识别器委托方法在滚动视图的子视图中拦截触摸。密切注意滚动视图的“可取消内容触摸”和“延迟内容触摸”属性。出于非常重要的原因,他们都是YES

您的滚动视图应该延迟内容触摸,直到它确定用户是否正在尝试点击、伪点击(如您所说)或滚动视图的平移。 Apple 已经编写了您正在尝试构建的功能; UIScrollView 已经可以做你想做的了。

问题是系统不希望滚动视图的子视图在滚动视图滚动时拦截点击事件。为此,如果它确定用户实际上正在尝试平移,它会取消触摸事件。设置“延迟内容接触”会启用此行为。确保它已打开,您应该没问题。

【讨论】:

  • 我已经尝试过使用它们(并且在 UITapGestureRecogniser 中使用相同的属性),但它根本没有产生任何结果。似乎此属性适用于低级别(使用 UIEvent 和 UITouch 而不是 UIGestureRecogniser)编码。或者我只是无法正确配置这些属性。
  • 这些低级事件与UIGestureRecognizer 一起使用。如果您移动手指,点击元素会导致点击手势识别器被取消。如果需要,您应该能够通过将 canCancelContentTouches 设置为 NO 来覆盖此行为,这应该会在内容视图的触摸开始跟踪后禁用拖动。
  • 我仍然无法得到我需要的东西。是否可以在不使用gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer: 方法的情况下实现此行为?如果可能比怎么做?如果滚动视图不滚动,没有它一切都好。为什么我在滚动时收不到点击动作?我已经厌倦了这些东西......
  • 我已经再次更新了我的答案,解释了发生了什么 -UIScrollView 只要启用它就已经具有此行为。
  • 感谢您的帮助。但是我运行你的项目,它有完全相同的问题:可以使点击同时导致点击和滚动。这不适合我。我正在尝试找到无法同时处理点击和滚动事件的解决方案。仅滚动或仅点击。并且在滚动时必须识别点击(没有新的滚动事件)。
【解决方案2】:

您也可以使用自定义委托方法,使用 @protocol。在添加了 UIScrollView 的视图控制器中实现这些委托方法。

喜欢 MyContentView

在touchesBegan方法中,

[self.delegate contentViewTapped:self];

现在在添加滚动视图的 ContainerView 类中,实现该方法:

 - (void)contentViewTapped:(MyContentView *)myContentView {

NSLog (@"ContentView no: %d", myContentView.tag); // if tag has been set while adding this view to scrollview.
}

浏览 @protocol 的示例。

希望这是您所需要的。

享受编码:)

【讨论】:

  • “在 touchesBegan 方法中”?似乎在这种情况下,每次我放下手指时我都会得到事件。但我只需要处理“真正的”点击事件。
  • 不,如果你担心的话,它不会影响你的滚动视图滚动事件。我已经在我的一个项目中做过这样的事情。
  • @mrunal 即使我正在寻找实现类似的东西。我的 ScrollView 执行为包含多个视图的 MainContainerView。现在我面临将 UIView 拖动到 ScrollView 中的特定位置的问题。我如何实现这一点,但我仍然找不到在 ScrollView.I 中放置它的位置已使用 Pan Gesture 进行相同操作。如何从 Gestures 调用触摸事件?
猜你喜欢
  • 1970-01-01
  • 2014-09-29
  • 1970-01-01
  • 1970-01-01
  • 2016-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多