自定义UIGestureRecognizer未按预期工作

时间:2011-06-26 15:50:44

标签: ios uitableview uigesturerecognizer

我有一个UITableView我在UIPopoverController中出现。表视图显示了可以拖放到主视图上的元素列表。

当用户在开始时开始主要是垂直的平移手势时,我希望UITableView像往常一样滚动。如果它一开始并不是垂直的,我希望应用程序将其解释为拖放操作。

不幸的是,我沿着这条道路漫长的旅程迫使我创建了一个自定义UIGestureRecognizer。为了使基础知识正确,我首先将这个自定义手势器留作空实现,只是调用Apple认为应该覆盖的五种自定义方法中的每一种的超级版本:

(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
(void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
(void)reset;

这导致什么都没发生,即从不调用自定义手势的动作方法,并且表视图像往常一样滚动。

在我的下一个实验中,我在UIGestureRecognizerStateBegan方法中将手势的状态设置为touchesBegan

这导致手势的动作方法触发,使手势看起来像标准UIPanGestureRecognizer。这显然表明我负责管理手势的状态。

接下来,我在UIGestureRecognizerStateChanged方法中将手势的状态设置为touchesMoved。一切都还不错。

现在,我尝试在UIGestureRecognizerStateFailed方法中将手势的状态设置为touchesMoved。我期待这个终止手势并将事件流恢复到表视图,但事实并非如此。它只是停止触发手势的动作方法。

最后,在我将UIGestureRecognizerStateFailed方法设置为touchesBegan后立即将手势的状态设置为UIGestureRecognizerStateBegan

这会导致手势恰好触发其动作方法一次,然后将所有后续事件传递给表视图。

所以...抱歉这么长的问题......但是为什么,如果我在touchesBegan方法中导致手势失败(首先将状态设置为UIGestureRecognizerStateBegan之后),那么正如预期的那样,将事件重定向到表视图。但是,如果我在touchesMoved中尝试相同的技术(我唯一可以检测到移动主要是垂直的),为什么不进行此重定向?

2 个答案:

答案 0 :(得分:1)

很抱歉让它比实际更复杂。经过大量的阅读和测试,我终于想出了如何做到这一点。

首先,创建自定义UIGestureRecognizer是解决此问题的正确方法之一,但是当我第一次测试空自定义识别器时,我犯了一个菜鸟错误:我忘了拨打{{1}对于我覆盖的每个方法。这没有导致任何事情发生,因此我将识别器的状态设置为[super touches...:touches withEvent:event]中的UIGestureRecognizerStateBegan,这导致操作方法被调用一次,因此说服我必须明确管理状态,这是只是部分正确。

实际上,如果您创建一个空的自定义识别器并在每个方法中调用适当的超级方法,那么您的程序将按预期运行。在这种情况下,将在整个拖动动作中调用动作方法。如果在touchesBegan中,您将识别器的状态设置为touchesMoved,则事件将冒泡到超级视图(在本例中为UIGestureRecognizerStateFailed),同样也符合预期。

我做出的错误,我认为其他人可能会认为,当您将手势识别器子类化时,设置手势的状态与标准方法的年表之间存在直接关联(即UITableView,{{1}等等)。没有 - 至少,它不是一个精确的映射。你最好让基本行为按原样运行,并且只在必要时进行干预。因此,在我的情况下,一旦我确定用户的拖动主要是垂直的,我只能在touchesBegan中进行,我在该方法中将手势识别器的状态设置为touchesMoved。这使识别器脱离了图片并自动将一整套事件转发到包含的视图。

为了简洁起见,我遗漏了大量通过本练习学到的其他东西,但是我想指出,在这个主题的六到七本书中,Matt Neuburg的编程IOS 4提供了最好的到目前为止对这个问题的解释。我希望本网站允许推荐。我与作者或出版商没有任何关系 - 只是感谢一个很好的解释!

答案 1 :(得分:0)

这可能是因为响应者希望从头到尾看到整个触摸,而不仅仅是一部分。通常,-touchesBegan:...设置一些状态,然后在-touchesMoved ...中进行修改,对于获得-touchesMoved的视图真的没有意义......没有先前收到-touchesBegan ......甚至有a note in the documentation部分地说:

  

处理触摸的所有视图,   包括你自己,期待(或应该   期待)接受完整的触摸事件   流。如果你阻止了UIKit   响应者对象来自接收   触及某个阶段的某个阶段   事件,结果可能是行为   未定义且可能不受欢迎。