Ответ
Обработка касаний в iOS построена на цепочке ответчиков (UIResponder) и системе распознавания жестов (UIGestureRecognizer). Процесс состоит из двух основных этапов.
1. Hit-Testing (Определение цели касания)
Система использует метод hitTest(_:with:) у корневого UIWindow, чтобы найти самый глубокий UIView, чья bounds содержит точку касания и у которого isUserInteractionEnabled = true. Этот view становится первым ответчиком (first responder) для события.
2. Доставка события
Событие касания (UITouch) передается для обработки. Существует два параллельных пути:
- Gesture Recognizers: Если к view или его иерархии присоединены распознаватели жестов (например,
UITapGestureRecognizer), они получают событие первыми. Если распознаватель распознает свой жест, он может потребовать отмены дальнейшей доставки события. - Цепочка UIResponder: Событие передается по цепочке ответчиков, начиная с первого ответчика (обычно это
UIView).class CustomView: UIView { override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { // Обработка начала касания super.touchesBegan(touches, with: event) // Передача дальше по цепочке } }Цепочка обычно идет:
UIView->UIViewController->UIWindow->UIApplication.
Важные особенности:
- Приоритет:
Gesture Recognizersимеют приоритет над стандартными методамиtouchesBeganи т.д. вUIResponder. UIControl(кнопки, слайдеры): Эти элементы используют паттерн target-action. Они обрабатывают касания внутренне и генерируют события (например,.touchUpInside), которые уже отправляются целям (targets), минуя сложную ручную обработку вUIResponder.- Отмена: Установка
isUserInteractionEnabled = falseилиisHidden = trueисключает view из hit-testing.
Ответ 18+ 🔞
А, ну это же классика, блядь! Система обработки тачей в iOS — это как многоэтажный бордель с чёткой иерархией, где каждый твой палец — это наглый посетитель, а вьюхи — это... ну, в общем, слушай сюда.
Короче, вся эта хуйня держится на двух китах, которые вечно спорят, кто первый обслужит клиента. Первый кит — это Hit-Testing, или «Кто тут крайний?».
Представь: тыкнул ты пальцем в экран. Окно (UIWindow), главный сутенёр, начинает орать метод hitTest(_:with:) на всю свою иерархию. Задача — найти самую глубоко сидящую вьюху, в чьи границы (bounds) попала точка, и чтобы у неё isUserInteractionEnabled был true. Нашлась — вот тебе и первый ответчик (first responder), лови клиента. Спряталась (isHidden = true) или «не трогать» (isUserInteractionEnabled = false) — мимо, иди ищи другую.
Дальше начинается цирк с конями, потому что доставка события идёт по двум параллельным путям, и они готовы друг друга переебать.
Путь первый: Распознаватели жестов (UIGestureRecognizer).
Это как быстрые и наглые охранники. Если они прицеплены к вьюхе или её предкам, они хватают событие ПЕРВЫМИ. Если охранник узнал в твоём движении свой родной жест (тап, пинч, свайп), он может взять и отменить дальнейшую доставку всем остальным. «Всё, клиент мой, разбирайтесь сами».
Путь второй: Цепочка ответчиков (UIResponder).
Это уже более размеренная, бюрократическая очередь. Событие начинают пинать по цепочке, начиная с того самого первого ответчика (вьюхи).
class CustomView: UIView {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// Ну вот, тронули нашу вьюху, блядь. Можно что-то сделать.
super.touchesBegan(touches, with: event) // А это — передать эстафетную палочку дальше, по инстанциям.
}
}
И пошло-поехало: UIView -> его UIViewController -> UIWindow -> UIApplication. Кто первый обработал — того и тапка.
А теперь, блядь, нюансы, от которых мозг вскипает:
- Кто главнее? Охранники-
GestureRecognizerпочти всегда важнее старичков-методовtouchesBegan/Moved/EndedвUIResponder. Они могут их просто отменить, ебать их в сраку. - Особые клиенты —
UIControl(кнопки, слайдеры). Эти ребята не ебутся с ручной обработкой. У них внутри своя, отлаженная схема «target-action». Тыкнули в кнопку — она внутри всё обработала и выстрелила готовым событием (типа.touchUpInside) прямо в привязанный метод. Никаких тебеtouchesBegan. Удобно, чо. - Как отменить всё нахуй? Выставь
isUserInteractionEnabled = falseилиisHidden = trueдля вьюхи. Её сразу вычеркнут из списка участников hit-testing'а, и она не получит ни хуя. Типа «не беспокоить».
Вот и вся магия, ёпта. С одной стороны — чёткая иерархия, с другой — постоянная подковёрная борьба за право первым поймать твой кривой тап.