Входит ли обработка gesture recognizers в responder chain в iOS?
Что проверяют
Знаете ли вы реальный путь касания в UIKit. Правильный ответ: нет, распознаватели жестов не входят в responder chain. Следом обычно спрашивают, что получит view, если жест распознан, и как разрулить конфликт двух жестов.
Как отвечать
- hit-testing:
UIWindowчерезhitTest(_:with:)иpoint(inside:with:)идёт сверху вниз по иерархии и находит самую глубокую view под пальцем; - распознаватели: окно отдаёт касания всем
UIGestureRecognizer, прикреплённым к этой view и её предкам, причём раньше, чем самой view.UIGestureRecognizerнаследуется отNSObject, а не отUIResponder, поэтому звеном цепочки не является; - что видит view: пока жест не распознан, view получает
touchesBeganи следующие вызовы. После распознавания приcancelsTouchesInView = true(это значение по умолчанию) ей приходитtouchesCancelled. Поведение настраиваютdelaysTouchesBeganиdelaysTouchesEnded; - responder chain: работает для необработанных касаний, которые view передаёт через
superкnext, а также для нажатий клавиш, motion-событий,UIKeyCommandи action-сообщений сnilв качестве цели. Направление обратное: от первого респондера вверх к контроллеру, окну иUIApplication.
Конфликты жестов решаются через require(toFail:) и делегат: gestureRecognizerShouldBegin(_:), gestureRecognizer(_:shouldRecognizeSimultaneouslyWith:), gestureRecognizer(_:shouldReceive:). Полезная деталь: у UIControl действие по умолчанию выигрывает у tap-жеста родительской view, поэтому кнопка внутри такой view продолжает нажиматься.
Где спотыкаются
Отвечают «да, входят», путая две разные системы доставки. Жест получает касания по иерархии view от hit-testing, а не по цепочке next.
Путают направления и говорят, что responder chain идёт от окна вниз. Вниз идёт hit-testing, цепочка поднимается вверх.
Вешают жест на UIImageView или UILabel и не понимают, почему он молчит. У них isUserInteractionEnabled по умолчанию false, и hit-testing их пропускает.