Почему hitTest: withEvent: вызывается три раза для каждого касания?

У меня есть подкласс UIView, в котором я переопределил hitTest:withEvent: следующим образом:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    NSLog(@"Event = %@", event);
    return self;
}

Для каждого касания в представлении я вижу три вызова hitTest:withEvent:. Эти три вызова выполняются до касания. Выход выглядит следующим образом:

2011-07-01 09:20:58.553 AppName[930:207] Event = <UITouchesEvent: 0x6a08360> timestamp: 4297.16 touches: {(
)}
2011-07-01 09:20:58.553 AppName[930:207] Event = <UITouchesEvent: 0x6a08360> timestamp: 4297.16 touches: {(
)}
2011-07-01 09:20:58.554 AppName[930:207] Event = <UITouchesEvent: 0x6a08360> timestamp: 4304.54 touches: {(
)}

На основе временных меток и адресов появляется, как будто используется один объект UITouchesEvent, а его временная метка неправильно настроена до третьего вызова. Может ли кто-нибудь объяснить, почему hitTest:withEvent: вызывается три раза? Я не ищу обходного пути. Я просто хочу понять, что происходит.

Ответ 1

У меня была такая же проблема, и я смог решить ее с помощью этого кода. Несмотря на то, что pointInside и hitTest вызываются 3 раза, touchBegan (или touchEnded) UIView, который был затронут, получает только один раз.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{   
    if (event.type == UIEventTypeTouches)
        NSLog(@"%@", self);
}


- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    if ([self pointInside:point withEvent:event])
        return self;

    return [super hitTest:point withEvent:event];
}

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    if (CGRectContainsPoint([self bounds], point))
    {
        if (event.type == UIEventTypeTouches)
        {           
            return YES;
        }
    }

    return NO;
}

Ответ 2

Есть ли у вас несколько подвью?

Из документов:

Этот метод перемещается по иерархии представлений, отправляя сообщение pointInside: withEvent: каждому подвью, чтобы определить, какой субвью должен получить событие касания. Если pointInside: withEvent: возвращает YES, то проходит иерархия subviews; в противном случае его ветвь иерархии представлений игнорируется. Вам редко нужно вызывать этот метод самостоятельно, но вы можете переопределить его, чтобы скрыть события касания от подзонов.

Ответ 3

Вы должны проверить, все ли свойства подтипа и типа. эти 3 события имеют смысл, поскольку там должно быть инициировано событие, чтобы ОС поняла природу события касания.

Например, проведите пальцем, зажмите и нажмите все, чтобы начать с того же события касания. Я предполагаю, что первые два уволены 1, чтобы зарегистрировать событие крана, а второе - для проверки события перехода на "перемещение". второй называется вскоре после этого, вероятно, либо отменить защемление/масштабирование/что угодно.

Внизу, в документах рассказывается о трех разных типах событий: о прикосновении, движении и удаленных событиях. Ссылка на класс UIEvent