如何取消一系列UITouch事件?

22

我有一个响应触摸事件的 UIImage 视图。如果触摸移动到特定区域之外,我想要取消触摸序列,也就是不再调用 touchesMoved:。如何实现呢?

我知道可以在 touchesMoved: 中检查触摸对象的坐标并忽略它,但我不知道如何彻底取消整个序列。在 苹果开发者的 UIResponder 参考文档 中,没有任何记录有关如何调用方法以取消触摸序列。


你能解决这个问题吗? - Gizmodo
12个回答

7
这个解决方案可能有些不太完美,但你可以实施并手动调用。
- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;

我基于在苹果iPhone示例代码网站上对MoveMe示例应用程序所做的一些调整,提出了这个解决方案。我修改了touchesMoved方法,使其看起来像这样:

- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
     UITouch *touch = [touches anyObject];
     if ([touch view] == placardView)
         CGPoint location = [touch locationInView:self];
         placardView.center = location;
         // I added the following line:
         [self touchesCancelled:touches withEvent:event];
         return;
}

1
谢谢,我回到我的 Mac 后会尝试一下。但这会取消后续的触摸事件吗?在我看来,在手动调用 touchesCancelled 后,touchesMoved 仍将被系统调用。 - subjective-c
在MoveMe示例代码的范围内,它将取消触摸,但我认为你是对的,touchesMoved仍然会被调用。我越想越觉得touchesCancelled不是正确的调用。 - Michael Fey
1
那样不行,而且“移动”事件会一直继续发生。 - pronebird

4

尝试将UIImageView的userInteractionEnabled属性临时设置为NO。


3

为了让父视图从事件中清理出来,您需要调用[super touchesMoved:withEvent:],但更重要的是,您不需要调用[super touchesCancelled:withEvent:]

这是我在检测到滑动时用于防止单元格被选中的代码:

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (!showingEdit) {
        if (IS_FAR_ENOUGH_TO_BE_A_SWIPE) {
            RESPOND_TO_SWIPE
            showingEdit = YES;
            [super touchesCancelled:touches withEvent:event];
        } else {
            [super touchesMoved:touches withEvent:event];
        }
    }
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    if (!showingEdit) {
        [super touchesEnded:touches withEvent:event];
    }
}

2

最近我也遇到了同样的问题,并找到了一个标准的解决方法。 您可以使用[[UIApplication sharedApplication] beginIgnoringInteractionEvents]停止将touchesMoved事件传递给整个应用程序。请确保在需要再次接收触摸时使用[[UIApplication sharedApplication] endIgnoringInteractionEvents]来启用它们。


2
我不认为这是可能的,因为我没有看到它有文档记录,而且这些解决方案都无法奏效。

1
我通过将视图从其父视图中移除并直接添加回来来实现这一点。
[view retain];
UIView *sv = view.superview;
[view removeFromSuperview];
[sv addSubview:view];
[view release];

这会打破响应者链到视图,因此任何剩余的触摸都不会在视图上接收到。下一个触摸仍将像往常一样被接收到。

1
“暴力”解决方案取决于它是否适合您的需求:删除并重新初始化接收触摸或响应它们的子视图(当然要注意框架和内容)。

0

我刚试着解决类似这样的问题,但发现这里列出的解决方案都对我无效。我最好的方法是暂时忽略触摸,但当触摸重新进入视图时它们又会继续。

最后终于解决了。

  1. 设置一个名为“disabled”的布尔标志
  2. 在touchedMoved中,首先检查触摸是否在所需视图内。如果不是,则将禁用标志设置为Yes。
  3. 仍在touchedMoved中,在执行操作之前检查标志。所以,在此时,如果它们在视图外部,就不会发生任何事情。
  4. 在touchesEnded中,将禁用标志设置为NO。因此,触摸序列实际上会停止,直到用户抬起手指。

我想,除非你有特定需要确切取消触摸序列,否则这个解决方案对你很有用。


你甚至可以使用单个标志来执行UIControl风格的跟踪,这比一次性取消整个事件序列更自然。 - pronebird

0
在iOS5中,UITouch似乎有一个私有方法。
-(void)setSentTouchesEnded:(BOOL)ended;

根据苹果的实现,它可能会停止发送事件

另一种方法是使用关联对象

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    if ([(NSNumber *)objc_getAssociatedObject(touch, &outKey) boolValue])
        return;
    if (sometouchisoutsideofview) {
        objc_setAssociatedObject(touch, &outKey, [NSNumber numberWithBool:YES], OBJC_ASSOCIATION_RETAIN);
    }
}

0
这段代码会对你有所帮助。我在touchesMoved:方法中禁用了触摸事件,并在touchesCancelled:方法中启用了触摸事件。
-(void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
     UITouch *touch = [touches anyObject];
     .......
     .......
     Your code
     .......
     .......

     //Condition when you want to disable touch event

     [[UIApplication sharedApplication] beginIgnoringInteractionEvents];

     .......
     .......
     Your code
     .......
     .......
 }


- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [[UIApplication sharedApplication] endIgnoringInteractionEvents];
}

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