iOS 7中手势识别器的问题 [英] Problems with gesture recognizer in iOS 7

查看:97
本文介绍了iOS 7中手势识别器的问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在屏幕上添加了几个 UIView 对象(例如5个),一个在另一个内。例如, view5.superview = view4 view4.superview = view3 view3 .superview = view2 view2.superview = view1 。对于所有这些 UIView 我设置了uitapgesturerecognizer;对于view1-4我只是在回调中执行NSLog(@tap%@,self),而对于view5,我设置以下内容:从层次结构中删除view4,然后将相同的对象view4'放在层次结构的同一位置。此对象还包含view5',其中设置了 UITapGestureRecognizer (实际上,我用类似的标记替换了标记的一部分)。

I'm adding several UIView objects (e.g. 5) to the screen, one inside the other. This, for example, view5.superview = view4, view4.superview = view3, view3.superview=view2, view2.superview = view1. For all these UIView I set uitapgesturerecognizer; for view1-4 I just do NSLog(@"tap %@", self) in callback, while for view5 tap I set the following: delete view4 from the hierarchy, then put the same object view4' at the same place of the hierarchy. This object also contains view5' for which UITapGestureRecognizer is set (practically, I replace one part of markup with similar one).

然后我开始点击view5。有些时候view5继续捕捉它的点击并且一切都没问题,但随后的点击随机数(每次这个数字不同)时,其中一个view1-4对象开始捕捉这个点击,尽管我们仍然点击了view5。整个问题具有随机特征 - 有时它发生在第10次发射,有时发生在第二次。有时错误的物体会在第一次敲击时开始捕捉水龙头。当一切都出错时,我也永远不知道哪个物体会碰到水龙头。用于视图(n + 1)的帧被设置为例如帧视图(n)的一半,而用于视图1的帧 - 例如(0,0 320,460)。

Then I start clicking on view5. Some time view5 keeps catching its tap and everything's OK, but random number of taps later (every time this number is different) one of the view1-4 objects starts catching this tap, though we're still clicking the view5. The whole problem has a random character - sometimes it occurs at the 10th launch, sometimes at the second. Sometimes wrong objects start catching taps at the first tap. Also I never know what object will catch a tap, when everything goes wrong. The frame for view(n+1) was set, e.g., as a half of the frame view(n), while the frame for view1 - e.g. (0,0 320, 460).

上面描述的ui对象的所有操作都是在主线程中进行的,我所说的一切都完全适用于iOS 4.3 - 6.1有更复杂的例子。但iOS7让它变成了一种随机的地狱。

All operations with ui objects described above are conducted in the main thread, and everything I've told about perfectly worked on iOS 4.3 - 6.1 with much more complex examples. But the iOS7 makes out of it some kind of a random hell.

更新:
我创建了一个示例项目,简化调试过程。无需添加/删除子视图操作。屏幕上只有4个视图,点按应用程序会记录所点击的视图。所以,你需要点击最小的视图(4)。如果你在日志中看到点击4点击4点击4 ... - 这就是一切正常,再次停止并再次运行,再次停止并再次运行等情况。在某些运行中(可能在10之后) +成功运行)你不会在第一行看到点击4,你会看到点击1或点击2或点击3,它会继续如此 - 这些都是坏情况。

Update: I've created a sample project, to simplify the debug process. No add/remove subview operations on tap. Only 4 views on screen, on tap the app logs what view was tapped. So, you need to tap on smallest view (4). If you see "tap 4 tap 4 tap 4…" in the log - this is the case when everything works fine, stop and run again, stop and run again, stop and run again, etc. And at some runs (maybe after 10+ successful runs) you won't see "tap 4" on the first line, you will see "tap 1" or "tap 2" or "tap 3", and it will continue so - these are the bad cases.

可从此处下载示例项目: http ://tech.octopod.com/test/BuggySample.zip (存档时只有33 Kb)。

Sample project can be downloaded from here: http://tech.octopod.com/test/BuggySample.zip (just 33 Kb in archive).

更新2

我们已经向Apple发布了一个错误,我会在这里发布一些反馈意见。但是,任何好的解决方法都会非常感激!

We've posted a bug to Apple, I'll post here when we will get some feedback. However, any good workaround would be much appreciated!

更新3

解决方案由Yuvrajsinh提供的是真正致力于样本项目。
不幸的是,它仍然没有帮助解决最初出现的主项目中出现的问题。现在的主要原因是,如果没有自我手势的任何视图都放在可点击内容上,则其下的随机视图元素开始捕捉交互(而不是具有交互手势集的顶部交互。
您有任何想法如何它可以解决吗?
更新的样本可以从这里下载: http:// tech.octopod.com/test/BuggySample2.zip

Solution, provided by Yuvrajsinh is really working on the sample project. Unfortunately, it still does not help to solve the problem that occurred in the main project where it initially appeared. The main reason for now is that if any view without self gesture is laying upon the clickable content, random view element under it starts catching the interaction (instead of the top one with interaction gesture set. Do you have any ideas how it can be solved? The updated sample can be downloaded from here: http://tech.octopod.com/test/BuggySample2.zip

推荐答案

因为问题只发生在iOS 7中,您可以使用其中一种新的委托方法来解决问题:

Because the problem is only occurring in iOS 7, you can use one of the new delegate methods to resolve the issue:

– gestureRecognizer:shouldRequireFailureOfGestureRecognizer:
– gestureRecognizer:shouldBeRequiredToFailByGestureRecognizer:

我通过实施 gestureRecognizer解决了这个问题:shouldBeRequiredToFailByGestureRecognizer 并抓取手势视图的超级视图,这样如果我上传,我可以返回是并且superview的手势等于提供的手势。我在此详细说明了我的完整分辨率: https://stackoverflow.com/a/19659848/1147934

I resolved it by implementing gestureRecognizer:shouldBeRequiredToFailByGestureRecognizer and "crawling" up the gesture's view's superview so I could return "YES" if I find the superview's gesture is equal to the one provided. I detail my full resolution here: https://stackoverflow.com/a/19659848/1147934.

解释


iOS 7中手势识别器的问题在于超级视图的手势接收之前的触摸其中一个子视图手势接收其触摸。这导致超视图手势识别然后取消子视图的识别器...这是(不正确?)并且已经向Apple提交了多个错误。有人指出,Apple不保证手势接收的顺序。我认为很多我们一直依赖于iOS 7中改变的实现细节。这就是为什么我们使用新的委托方法,这些方法似乎旨在帮助我们解决这个问题。

Explanation
The problem with gesture recognizers in iOS 7 is that a superview's gesture is receiving its touches before one of its subview gestures receives its touches. This causes the superview gesture to recognize which then cancels out the sub view's recognizer... this is (incorrect?) and multiple bugs have been filed with Apple. It's been pointed out that Apple doesn't guarantee the order in which gestures receive touches. I think a lot of "us" have been relying on an implementation detail that changed in iOS 7. This is why we use the new delegate methods, which seem designed to help us address this problem.

注意:我通过使用自己的sublcassed识别器进行了大量测试,记录所有触摸并发现原因识别器失败的原因是superview手势在子视图的手势处于关注状态之前接收到触摸~5%的病例。每次发生这种情况,都会发生失败。如果您拥有带有大量手势的深层次层次结构,则会更频繁地发生这种情况。

Note: I did extensive testing by using my own sublcassed recognizers, logging all touches and discovered that the reason recognizers fail is because superview gestures were receiving touches before a subview's gesture was in about ~5% of the cases. Every time this happened, failure occurred. This does happen more often if you have "deep" hierarchies with lots of gestures.

新的委托方法可能令人困惑,因此您需要仔细阅读。

The new delegate methods can be confusing, so you need to read them carefully.

我正在使用该方法(我已重命名参数以使其更易于理解)

I'm using the method (I've renamed the arguments to make them easier to understand)

- gestureRecognizer:(UIGestureRecognizer *)thisRecognizer shouldBeRequiredToFailByGestureRecognizer:(UIGestureRecognizer *)otherRecognizer

如果您返回是,则提供的手势识别器 otherRecognizer 将需要 thisRecognizer 在被识别之前失败。这就是为什么在我的回答中,我爬上superview层次结构来检查它是否包含具有 otherRecognizer 的超级视图。如果是,我希望 otherRecognizer 要求 thisRecognizer 失败,因为 thisRecognizer 处于子视图中且失败,然后才会识别出superview的手势。这将确保在超级视图的手势之前识别子视图手势。有意义吗?

If you return "YES", then the gesture recognizer provided, otherRecognizer, will require thisRecognizer to fail before it can be recognized. This is why, in my answer, I crawl up the superview hierarchy to check if it contains a superview that has the otherRecognizer. If it does, I want otherRecognizer to require thisRecognizer to fail because thisRecognizer is in a subview and should fail before it's superview's gesture is recognized. This will make sure that subview gestures are recognized before their superview's gestures are. Make sense?

替代

我可以反过来使用:

Alternative
I could go about it the other way around and use:

- gestureRecognizer:(UIGestureRecognizer *)thisRecognizer shouldRequireFailureOfGestureRecognizer:(UIGestureRecognizer *)otherRecognizer

现在我需要抓取整个子视图层次结构,检查 otherRecognizer 是否在其中并返回 YES 如果是的话。我不使用这种方法,因为爬行整个子视图层次结构比检查超级视图层次结构要困难得多,而且成本高昂。爬行子视图层次结构必须是递归函数,而我可以使用简单的循环来检查superview的层次结构。所以我推荐我概述的第一种方法。

Now I would need to crawl through my entire subview hierarchy, check if otherRecognizer is in it and return YES if it is. I don't use this method because crawling the entire subview hierarchy is much more difficult and expensive to do than to check a superview hierarchy. Crawling a subview hierarchy would have to be a recursive function, while I can use a simple while loop to check a superview's hierarchy. So I recommend the first approach I outline.

警告!

小心一下使用 gestureRecognizer:shouldReceiveTouch:。问题是哪个手势首先接收触摸(取消另一个手势)的问题......这是解决冲突的问题。如果您实现 gestureRecognizer:shouldReceiveTouch:,如果子视图手势失败,您可能会拒绝超级视图的手势,因为当子视图手势猜测 >可能
被识别。子视图手势可能由于触摸超出界限而合法地失败,因此您必须知道实现细节才能正确猜测。当子视图手势失败时,您想要超级视图手势被识别,但您实际上并不确定它是否会在实际失败之前失败。如果子视图手势失败,通常您希望超视图手势随后识别。这是正常的响应者链(子视图超级视图),如果你搞砸了,你最终会出现意外行为。

Warning!
Be careful about using gestureRecognizer:shouldReceiveTouch:. The issue is a problem of which gesture receives touches first (canceling the other gesture out)... it's a problem of conflict resolution. If you implement gestureRecognizer:shouldReceiveTouch:, you risk rejecting a superview's gesture if the subview gesture fails because you have to guess when a subview gesture might be recognized. A subview gesture may legitimately fail for reasons other than the touches are out of bounds, so you would have to know implementation details in order to guess correctly. You want the superview gesture to be recognized when the subview gesture fails but you don't really have anyway to know for certain if it will fail before it actually fails. If a subview gesture fails, normally you want the superview gesture to then recognize. This is the normal responder chain (subview superview) and if you mess with that you could end up with unexpected behavior.

这篇关于iOS 7中手势识别器的问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆