iOS теряет касания?

Я не могу найти ничего, чтобы объяснить потерянные события UITouch. Если вы ударите свою полную руку по экрану достаточно раз, количество касаний Began будет отличаться от количества касаний закругленных! Я думаю, что единственный способ узнать об этих осиротевших прикосновениях самому - это сослаться на них и отследить, как долго они не двигались.

Образец кода:

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];
}

3 ответа

Не забывайте о touchesCancelled: Ссылка на UIResponder

Редактирование в ответ на обновление постера:

Каждый сенсорный объект указывает, в какой фазе он находится:

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);
}

Каждое сенсорное событие будет проходить через обе фазы: начатое и завершенное / отмененное, поэтому ваши показатели должны совпадать, как только ваши пальцы исчезнут с экрана.

Одна вещь, которую нужно помнить... Вы можете получить несколько касаний, которые имеют несколько нажатий. Не забудьте принять во внимание tapCount.

Однако, если у вас все еще есть проблема, вы можете рассмотреть все прикосновения к событию, хотя оно представляет некоторые другие проблемы управления...

HACK ALERT

Я закодировал следующий 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];
}

Затем, назовите его в конце прикосновения Начал и коснулся Перемещено...

[self touchesEndedOrCancelled:event.allTouches];

Чтобы это работало, touchesEnded/Cancelled не должно подавляться событием с нулевым значением. Кроме того, "другое" должно быть обработано. В касаниях закруглил...

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

и в контакте отменил...

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

Возможно, вам придется предоставить более подробную информацию, но....

Если вы проведете пальцем по краю экрана, это событие покажет, что касание запущено и касание перемещено, но не заканчивается, поскольку оно фактически не заканчивалось (поднимите палец). Это может быть вашей проблемой, что событие не произошло. Кроме того, существует ограничение на количество касаний в режиме мультитач, если вы нажимаете, скажем, 10 раз, а затем до системы, чтобы определить, какие события на самом деле, а какие ложные, кажется, что вы используете оборудование неправильно.

Другие вопросы по тегам