8

我找不到任何东西来解释丢失的 UITouch 事件。如果您将整只手砸在屏幕上的次数足够多,则 touchesBegan 的次数将与 touchesEnded 的次数不同!我认为真正了解这些孤立触摸的唯一方法是自己参考它们并跟踪它们多久没有移动。

示例代码:

int touchesStarted = 0;
int touchesFinished = 0;

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    touchesStarted += touches.count;
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    touchesFinished += touches.count;
    NSLog(@"%d / %d", touchesStarted, touchesFinished);
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self touchesEnded:touches withEvent:event];
}
4

3 回答 3

5

不要忘记touchesCancelledUIResponder 参考

编辑以响应海报的更新:

每个触摸对象都提供了它所处的阶段:

typedef enum {
    UITouchPhaseBegan,
    UITouchPhaseMoved,
    UITouchPhaseStationary,
    UITouchPhaseEnded,
    UITouchPhaseCancelled,
} UITouchPhase;

我相信,如果触摸在同一个触摸事件集中开始和结束,-touchesBegan:withEvent:将被调用,但将包含已结束或取消的触摸

然后,您应该将计数代码更改为如下所示:

int touchesStarted = 0;
int touchesFinished = 0;

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self customTouchHandler:touches];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self customTouchHandler:touches];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self customTouchHandler:touches];
}
- (void)customTouchHandler:(NSSet *)touches
{
    for(UITouch* touch in touches){
        if(touch.phase == UITouchPhaseBegan)
            touchesStarted++;
        if(touch.phase == UITouchPhaseEnded || touch.phase == UITouchPhaseCancelled)
            touchesFinished++;
    }
    NSLog(@"%d / %d", touchesStarted, touchesFinished);
}

每个触摸事件都会经历开始和完成/取消的两个阶段,因此一旦手指离开屏幕,您的计数应该匹配。

于 2012-02-16T23:56:28.873 回答
3

要记住的一件事...您可能会收到一些具有多次点击的触摸。不要忘记将 tapCount 考虑在内。

但是,如果您仍然有问题,您可以考虑事件的所有接触,尽管它会带来一些其他管理问题......

黑客警报

我已经编写了以下HACK来解决这个问题。有时 touchesEnded 不会被调用,但是,触摸显示为事件中所有触摸的一部分。

请注意,您现在可以多次处理相同的“取消”或“结束”触摸。如果这是一个问题,您必须保持自己的“待处理”触摸状态,并在完成后将其删除。

是的,这一切都很糟糕,但如果没有类似的黑客攻击,我不知道如何克服这个问题。基本的解决方案是查看每个事件中的所有触摸,并根据它们的阶段处理它们,在看到它们时调用适当的结束/取消。

- (void) touchesEndedOrCancelled:(NSSet *)touches
{
    __block NSMutableSet *ended = nil;
    __block NSMutableSet *canceled = nil;
    [touches enumerateObjectsUsingBlock:^(UITouch *touch, BOOL *stop) {
        if (touch.phase == UITouchPhaseEnded) {
            if (!ended) ended = [NSSet setWithObject:touch];
            else [ended addObject:touch];
        } else if (touch.phase == UITouchPhaseCancelled) {
            if (!canceled) canceled = [NSSet setWithObject:touch];
            else [canceled addObject:touch];
        }
    }];
    if (ended) [self touchesEnded:ended withEvent:nil];
    if (canceled) [self touchesCancelled:canceled withEvent:nil];
}

然后,在 touchesBegan 和 touchesMoved 结束时调用它...

[self touchesEndedOrCancelled:event.allTouches];

为此,touchesEnded/Canceled 不需要在 nil 事件上阻塞。此外,需要处理“其他”。在接触结束...

[self touchesCancelled:[event.allTouches objectsPassingTest:^BOOL(UITouch *touch, BOOL *stop) {
    return touch.phase == UITouchPhaseCancelled;
}] withEvent:nil];

并在 touchesCanceled...

[self touchesEnded:[event.allTouches objectsPassingTest:^BOOL(UITouch *touch, BOOL *stop) {
    return touch.phase == UITouchPhaseEnded;
}] withEvent:nil];
于 2012-04-20T03:23:37.950 回答
0

您可能需要提供更多详细信息,但......

如果您将手指从屏幕边缘移开,此事件将显示触摸开始和触摸移动但没有结束,因为它实际上并没有结束(抬起手指)。这可能是你的问题,事件没有发生。另外,如果您按 10 次多点触控的次数,那么多点触控的数量是有限制的,然后由系统来确定哪些事件是真实的,哪些是错误的,看起来您使用的硬件不正确。

于 2012-04-26T09:23:20.107 回答