#objective-c #cocoa-touch #ios #uiscrollview
#objective-c #cocoa-touch #iOS #uiscrollview
Вопрос:
У меня есть UIScrollView
без вложенных представлений. Когда я перетаскиваю вид прокрутки, он hitTest:withEvent:
вызывается три раза, и в событии никогда не происходит никаких касаний. Почему это (я видел другой пост, но, похоже, у него нет conclusion)? Вот журнал просмотра прокрутки hitTest...
и pointInside:withEvent:
2011-05-11 20:12:37.472 MyApp[10909:707] тест попадания для UIScrollView 119.500000, 102.000000, временная метка: 357978 касания: {()} 2011-05-11 20:12:37.475 MyApp[10909:707] Указывает на UIScrollView 119.500000, 102.000000, временная метка: 357978 касания: {()} 2011-05-11 20:12:37.477 MyApp [10909:707] тест попадания для UIScrollView 119.500000, 102.000000, временная метка: 357978 касания: {()} 2011-05-11 20:12:37.479 MyApp[10909:707] Указывает на UIScrollView 119.500000, 102.000000, временная метка: 357978 касания: {()} 2011-05-11 20:12:37.481 MyApp[10909:707] тест попадания для UIScrollView 119.500000, 102.000000, временная метка: 358021 касания: {()} 2011-05-11 20:12:37.482 MyApp[10909:707] Указывает на UIScrollView 119.500000, 102.000000, временная метка: 358021 касания: {()} 2011-05-11 20:12:37.484 MyApp[10909:707] Указывает на UIScrollView 119.500000, 396.000000, временная метка: 358021 касания: {()}
Комментарии:
1. Я сам нашел точно такую же вещь в пользовательском подклассе UIView. Я переопределил метод hitTest: withEvent: для выполнения некоторой пользовательской обработки и подумал, что множественные вызовы были вызваны каким-то неправильным кодом, но, читая здесь, кажется, что это особенность обработки событий iOS. Было бы интересно узнать, почему необходимы три вызова.
2. Не уверен, что это ответ, поэтому я опубликую его здесь … предполагая, что ваша иерархия такова: UIWindow —> UIView от UIViewController -> UIScrollView, возможно ли, что вы получаете тест на попадание для каждого представления «hittable» в иерархии? В документации указано, что pointInside вызывается ниже по иерархии. Добавьте UIView в свой вид прокрутки и посмотрите, вызовете ли вы его 4 раза. Другая идея заключается в том, что это дает вам 3, чтобы вы могли получить среднее значение.
Ответ №1:
hitTest:
это служебный метод, предназначенный для поиска представления в определенной точке. Это НЕ означает, что пользователь нажимает на сенсорный экран. Вполне разумно, чтобы hitTest вызывался несколько раз в ответ на одно и то же событие; все, что должен делать метод, это возвращать представление под точкой, и это НЕ должно вызывать никаких побочных эффектов.
Если вы хотите отслеживать события касания, вам следует переопределить touchesBegan:
и друзей.
Ответ №2:
У меня была такая же проблема, и я на самом деле не нашел ответа на это, но вы могли бы использовать одно из этих двух решений:
1. Сохраните тесты попадания в массив и сравните их, чтобы вы могли вернуться, когда результат будет одинаковым, чтобы предотвратить его вызов 3 раза подряд.
2. Вместо hittest используйте touchesBegan, touchesCancelled, touchesEnded и touchesMoved следующим образом:
- (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);
}
Я использовал решение touchesBegan и т.д., И оно работает просто великолепно 🙂
Ответ №3:
Я не знаю наверняка, почему, но вот некоторые дополнительные сведения по этому вопросу:
- Похоже, это не относится конкретно к UIScrollView. Я запустил тест с UIView — те же результаты.
- Кажется, что он вызывается три раза в корневом представлении независимо от иерархии представлений или возвращаемого значения.
- Событие, переданное в hitTest, в основном пустое для первых двух вызовов (но точка всегда действительна); событие имеет действительную временную метку, но нет информации о касании для третьего вызова.
- Похоже, что
UIResponder
методы вызываются только после завершения всех трех вызовов hitTest. Например, touchesBegan:withEvent: не будет вызываться до конца. - Все три вызова исходят из разных точек в (я полагаю, с закрытым исходным кодом) функции UIApplicationHandleEvent, основанной на трассировках стека.
Мое лучшее предположение заключается в том, что в некоторых случаях возвращаемое значение из hitTest
может меняться между вызовами. Однако я не могу понять, почему это может произойти. Если это не так, то нет смысла вызывать это несколько раз.
Другая идея заключается в том, что код просто написан неэффективно. Это кажется менее вероятным, но, основываясь на этой информации, это возможно.
Комментарии:
1. Я настроил проект с видом прокрутки, расположенным в представлении VC, и выполнил проверку попадания случайной точки в viewDidAppear. Я получаю только 1 вызов. Куда вы вызываете hitTest?
2. Также пробовал перехватывать события в UIWindow и удалять / разрывать цепочку ответчиков и т.д. Я все еще озадачен! 🙂