在UIScrollView中滚动而不触发touchesCancelled事件

10

概述

我正在开发一个iPhone游戏,其代码是从另一位开发者那里继承的。游戏网格是一个UIScrollView,其contentSize为1000x1000。该网格包含通过OpenGL的Texture2D类在屏幕上绘制的几个元素。

UIScrollView沿着与您的手指相反的方向滚动。其背后的想法是模拟使用手指“筛选”元素的行为,因为触摸路径上的每个元素都应受到影响/操作。

 

问题

问题是UIScrollView的滚动会触发touchesCancelled,从而结束游戏所依赖的touchesMoved调用,以了解要操作哪些元素。即使我的手指移动不会在视图中触发滚动,将手指移动超过10个像素的距离也会触发touchesCancelled方法,从而结束未来的touchesMoved调用,直到我抬起手指并开始新的触摸事件。

我确信是滚动事件触发了touchesCancelled方法,因为如果我在视图上设置self.scrollingEnabled = NO;,在屏幕上移动手指会像应该一样继续触发touchesMoved,无论我在屏幕上移动手指多远,当我抬起手指时,touchesEnded会按预期调用(在我完成筛选元素后),并且触摸路径上的每个元素确实会被操作。然而,设置此属性自然会阻止游戏网格的所需滚动。

 

尝试解决问题但失败的方法

我尝试在视图的initWithFrame方法中设置self.canCancelContentTouches = NO;,但是仍然会触发touchesCancelled,不确定为什么会这样!也许我把它放错了位置,但是我不确定这是否是我的问题解决方案,因为文档表明这样的设置会防止滚动: "If the value of this property is NO, the scroll view does not scroll regardless of finger movement once the content view starts tracking." 显然这不是我想要的行为,因此该属性似乎并不是我感兴趣的。虽然我仍然困惑于为什么它仍然会滚动并调用touchesCancelled,但我偏离了主题。
我还添加了方法- (BOOL)touchesShouldCancelInContentView:(UIView *)view,但它没有被调用,甚至没有设置self.canCancelContentTouches = NO;作为文档指出,将canCancelTouches属性设置为NO确实会阻止调用touchesShouldCancelInContentView方法:"The scroll view does not call this method if the value of the canCancelContentTouches property is NO." 虽然文档似乎不清楚从这种方法返回NO是否也会像canCancelContentTouches = NO;设置那样防止滚动。如果不是,则应该是理想的解决方案。再次提醒一下,我不知道为什么甚至没有调用此方法,因为文档只提到一个阻止其被调用的属性/设置,即使该属性未被设置为NO(因此默认为YES),它仍然没有被调用。
那么现在我不知道该怎么办了。事实是,视图开始滚动后,我仍需要继续调用touchesMoved。是否可能?如果不行,我有哪些选择?

嗯...只是一个想法。为什么你不能控制滚动呢?因为据我所理解,你可以根据手指相对于屏幕中心的位置来滚动视图。 - govi
听起来是一个有趣的方法,但我该怎么做呢?我在UIScrollView文档中没有看到任何方法似乎能够处理手动滚动。 - purefusion
2个回答

9

我曾经遇到过完全相同的问题(并且浪费了很多时间)。 后来我尝试尽早设置cancelsTouchesInView属性(我在viewDidLoad中执行)... 然后它对我起作用了(如此处所示)!

- (void)viewDidLoad {
    [super viewDidLoad];
    /* other initializations */
    scrollView.panGestureRecognizer.cancelsTouchesInView = NO;
}

这个在iOS 5中可以使用。在iOS 5之前,您需要浏览所有的识别器,找到panGestureRecognizer,然后设置属性。因此,这应该是一个通用的解决方案:

- (void)viewDidLoad {
    [super viewDidLoad];
    /* other initializations */
    for (UIGestureRecognizer *gesture in scrollView.gestureRecognizers){
        if ([gesture isKindOfClass:[UIPanGestureRecognizer class]]){
        gesture.cancelsTouchesInView = NO;    
    }
}

我在我的UIScrollView视图子类中使用了这种方法。它在-initWithFrame:-viewDidLoad中同样有效。我还使用了运行时测试来查看[self respondsToSelector:@selector(panGestureRecognizer)]是否可用以切换实现方式。 - macserv

0
- (void)scrollRectToVisible:(CGRect)rect animated:(BOOL)animated 

这可能会起作用... 任何touchesMoved都可以触发一个方法,该方法将以与屏幕中心(或任何其他位置)和上次记录的触摸位置之间的距离成比例的速度滚动,直到touchesEnded。


我认为这个方法不是你所描述的那样。它只是将指定的CGRect滚动到视图中。它与触摸无关。我不认为这对我有用。 - purefusion

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