Ответ
Hit-Testing — это процесс определения, какое представление (UIView) должно получить событие касания. Он запускается при каждом новом касании (touch event) системой UIApplication.
Алгоритм (метод hitTest(_:with:)):
Процесс рекурсивный, начинается с корневого окна (UIWindow) и идет от верхних вью к нижним.
- Проверяются условия для текущей вью:
isUserInteractionEnabled == trueisHidden == falsealpha > 0.01- Точка касания находится внутри границ вью (
bounds).
- Если условия не выполнены – вью и всё её поддерево игнорируются.
- Если условия выполнены, алгоритм проходит по массиву
subviewsв обратном порядке (от последней добавленной, которая визуально выше, к первой). - Для каждой сабвью рекурсивно вызывается
hitTest. - Если сабвью возвращает не-
nil(нашла подходящую вью), этот результат возвращается. - Если ни одна сабвью не вернула результат, возвращается сама текущая вью.
Пример переопределения для расширения области касания:
class CustomButton: UIButton {
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
// 1. Проверяем стандартные условия
guard self.isUserInteractionEnabled,
!self.isHidden,
self.alpha > 0.01 else {
return nil
}
// 2. Расширяем область проверки на 20 пунктов во все стороны
let expandedBounds = bounds.insetBy(dx: -20, dy: -20)
// 3. Если точка в расширенной области, возвращаем self (эту кнопку)
if expandedBounds.contains(point) {
return self
}
// 4. Иначе передаем обработку стандартному алгоритму
return super.hitTest(point, with: event)
}
}
Итог: Hit-Testing гарантирует, что событие касания получает самый глубокий (верхний в иерархии) UIView, готовый его обработать.