Ответ
Эти методы работают в тандеме для определения получателя touch-событий в иерархии UIView.
point(inside:with:)
- Назначение: Проверяет, находится ли заданная точка в пределах границ (bounds) текущего view.
- Возвращает:
Bool(true, если точка внутри). - Логика: Простая геометрическая проверка. Не учитывает иерархию subviews.
- Типичное использование: Переопределяется для расширения или изменения области отклика view без изменения его видимых границ.
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { // Увеличиваем область отклика на 10 пунктов во все стороны let expandedBounds = bounds.insetBy(dx: -10, dy: -10) return expandedBounds.contains(point) }
hitTest(_:with:)
- Назначение: Определяет самое глубокое (frontmost) view в иерархии, которое должно получить touch-событие для заданной точки.
- Возвращает:
UIView?(найденное view илиnil). - Алгоритм работы (рекурсивный):
- Проверяет, может ли view вообще получать события:
isUserInteractionEnabled,!isHidden,alpha > 0.01. - Вызывает
point(inside:with:)для себя. Если точка вне границ — возвращаетnil. - Если точка внутри, проходит по subviews в обратном порядке (от самого верхнего к нижнему), вызывая для каждого
hitTest. - Если один из subviews вернул не-nil view, возвращает его. Если нет — возвращает себя.
- Проверяет, может ли view вообще получать события:
- Типичное использование: Переопределяется для перенаправления событий или создания нестандартного поведения (например, игнорирование touches в определенной области).
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { let hitView = super.hitTest(point, with: event) // Если событие должно попасть в прозрачную кнопку-оверлей, возвращаем её return (hitView == self) ? overlayButton : hitView }
Взаимосвязь: hitTest использует point(inside:with:) как один из шагов в своем алгоритме. Переопределение point(inside:with:) напрямую влияет на результат работы hitTest для этого view.
Ответ 18+ 🔞
А, ну это ж классика, блядь! Эти два метода — как Герасим и его Муму, один другого кормит, а потом оба в озеро летят, если не разобраться. Слушай, сейчас разжую, как сука, чтобы понятно было.
Вот представь себе, блядь, у тебя на экране эта пирамида из вьюх, как матрёшки, одна в другой. Палец тыкнул — кому событие достанется? А вот эти два мудака и решают, ёпта!
point(inside:with:) — это как охранник у двери, тупой и прямолинейный.
Его задача — чисто геометрическая, блядь. Стоит на входе в конкретный клуб под названием «Вьюха» и орет: «Эй, ты, точка! Ты внутри моих границ? Да или нет?». Никаких subviews, никакой иерархии — просто прямоугольник. bounds.contains(point), и всё, пиздец.
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
// Делаем зону отклика побольше, чтоб даже криворукие попали
let expandedBounds = bounds.insetBy(dx: -10, dy: -10)
return expandedBounds.contains(point) // true/false, и нехуй тут
}
Переопределяешь его, когда тебе надо, чтоб кнопка откликалась, даже если тыкнул рядом, или наоборот — чтоб игнорировал дырку посередине. Охранник просто расширил или сузил проход, блядь.
hitTest(_:with:) — это уже главный администратор всего этого борделя.
Он умный, рекурсивный и знает всю иерархию наизусть. Его работа — найти самую верхнюю, самую глубоко сидящую вьюху, которой и вручить этот самый touch. Алгоритм у него, блядь, строгий:
- Фильтр дебилов: Смотрит на вьюху — включен ли юзер-интеракшен, не спрятана ли, альфа не нулевая? Если что-то не так — сразу
nil, иди нахуй, не кондиция. - Вызов охранника: Кричит тому самому
point(inside:with:): «Эй, охранник! Эта точка у нас в клубе?». Если нет — опятьnil, мимо проходили. - Рекурсивный обход: Если точка внутри, он начинает опрашивать всех своих subviews, но с конца, с самого верхнего (потому что тот поверх всех лежит, его и трогают первым). Каждому задаёт тот же вопрос: «А у тебя кто внутри сидит?».
- Вердикт: Если какой-то subview нашёлся и вернул себя — его и отдаём. Если все subviews пустые — ну значит, событие этому самому родителю и достаётся, он и есть самый глубокий.
Переопределяешь его, когда надо событие перенаправить, ёбана. Например, твоя вьюха прозрачная, но через неё должна тыкаться кнопка-оверлей.
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
let hitView = super.hitTest(point, with: event) // спросим у предка
// Если событие пришло ко мне самому, а не к детям — отдадим его оверлейной кнопке
return (hitView == self) ? overlayButton : hitView
}
А связь-то, блядь, в чём? Да в том, что hitTest использует point(inside:with:) на каждом шагу! Это как система, ёпта. Охранник говорит «не пущаю» — администратор даже не станет внутрь смотреть. Переопределил point — автоматически изменил логику для hitTest. Один другого кормит, пока не прикажут собаку утопить, вот и вся философия, в рот меня чих-пых!