UIView hitTest: withEvent: звонки входят в тройку

У меня есть UIScrollView без подсмотров. Когда я перетаскиваю вид прокрутки, его hitTest:withEvent: вызывается три раза, и в событии никогда не происходит никаких касаний. Почему это (я видел еще одну запись, но она, похоже, не имеет сговор)? Вот журнал просмотра прокрутки hitTest... и pointInside:withEvent:

2011-05-11 20:12:37.472 MyApp[10909:707] hit test for UIScrollView 119.500000,102.000000, timestamp: 357978 touches: {()}
2011-05-11 20:12:37.475 MyApp[10909:707] pointInside for UIScrollView 119.500000,102.000000,  timestamp: 357978 touches: {()} 
2011-05-11 20:12:37.477 MyApp[10909:707] hit test for UIScrollView 119.500000,102.000000, timestamp: 357978 touches: {()}
2011-05-11 20:12:37.479 MyApp[10909:707] pointInside for UIScrollView 119.500000,102.000000,  timestamp: 357978 touches: {()} 
2011-05-11 20:12:37.481 MyApp[10909:707] hit test for UIScrollView 119.500000,102.000000, timestamp: 358021 touches: {()}
2011-05-11 20:12:37.482 MyApp[10909:707] pointInside for UIScrollView 119.500000,102.000000,  timestamp: 358021 touches: {()} 
2011-05-11 20:12:37.484 MyApp[10909:707] pointInside for UIScrollView 119.500000,396.000000,  timestamp: 358021 touches: {()} 

Ответ 1

hitTest: - это метод утилиты, предназначенный для поиска представления в определенной точке. Он НЕ представляет пользователя, нажав на сенсорный экран. Совершенно разумно, чтобы hitTest вызывался несколько раз в ответ на одно и то же событие; весь метод должен сделать, это вернуть представление под точкой и НЕ ДОЛЖЕН запускать любые побочные эффекты.

Если вы хотите отслеживать события касания, вы должны переопределить touchesBegan: и друзей.

Ответ 2

У меня была такая же проблема и на самом деле не нашел ответа на этот вопрос, но вы могли бы использовать одно из этих двух решений:

1. Храните тесты ударов в массиве и сравнивайте их, чтобы вы могли вернуться, когда они будут одинаковыми, чтобы предотвратить его вызов 3 раза подряд.

2. Вместо hittest, используйте touchBegan, touchsCancelled, touchEnded и touchsMoved вот так:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch * touch = [[event allTouches] anyObject];
    CGPoint touchLocation = [touch locationInView:touch.view];
    NSLog(@"%f - %f", touchLocation.x, touchLocation.y);
}

Я использовал приложение touchhesBegan и т.д., и он работает как шарм:)

Ответ 3

Я не знаю точно, почему, но вот некоторые дополнительные сведения по этому вопросу:

  • Это не похоже на UIScrollView. Я проверил тест с UIView - те же результаты.
  • Кажется, он трижды появляется в корневом представлении независимо от иерархии представления или возвращаемого значения.
  • Событие, переданное hitTest, в основном пустое для первых двух вызовов (но точка всегда действительна); событие имеет действительную временную метку, но не имеет сенсорной информации для третьего вызова.
  • Похоже, что методы UIResponder не вызываются до тех пор, пока не будут завершены все три вызова hitTest. Например, touchBegan: withEvent: не будет вызываться до конца.
  • Все три вызова происходят из разных точек в функции (с закрытым исходным кодом, я полагаю) UIApplicationHandleEvent, на основе трассировок стека.

Мое лучшее предположение заключается в том, что в некоторых случаях возвращаемое значение из hitTest может меняться между вызовами. Я не могу придумать, почему это может произойти. Если это неверно, тогда нет смысла называть его несколько раз.

Другая идея состоит в том, что код просто неэффективно написан. Это кажется менее вероятным, но на основе этой информации это возможность.