Можно ли обработать событие касания, если у UIView свойство isUserInteractionEnabled установлено в false?

Ответ

Нет, напрямую — нельзя. Когда isUserInteractionEnabled = false, система UIKit полностью игнорирует все жесты и касания на этом представлении. Однако существуют обходные пути для перехвата событий:

1. Прозрачное наложение (Overlay View)

Добавьте поверх целевой вью прозрачное представление с включенным взаимодействием.

let overlay = UIView(frame: targetView.bounds)
overlay.isUserInteractionEnabled = true
targetView.addSubview(overlay)
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
overlay.addGestureRecognizer(tapRecognizer)

2. Переопределение hitTest(_:with:)

Можно перехватить и перенаправить события, переопределив метод hitTest в кастомной вью.

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    let hitView = super.hitTest(point, with: event)
    // Возвращаем nil для себя, чтобы события прошли "сквозь" эту вью
    return hitView == self ? nil : hitView
}

3. Программный вызов действий (для UIControl)

Для элементов UIControl (кнопки, слайдеры) можно использовать метод sendActions(for:) для программной отправки событий.

button.sendActions(for: .touchUpInside)

Важно: Эти методы являются обходными и могут усложнить архитектуру. Основное правило — если вью должна реагировать на касания, isUserInteractionEnabled должно быть true.

Ответ 18+ 🔞

А, ну это же классика, блядь! Ситуация, когда ты пытаешься ткнуть в кнопку, а она как будто из другого измерения, нихуя не реагирует. isUserInteractionEnabled = false — это как повесить на дверь табличку «Не еби мозги, я в отпуске». Система тупо смотрит на это и говорит: «Ну всё, пошёл нахуй, чувак, не моё дело».

Но мы же не ищем лёгких путей, правда? Нам надо, чтобы эта штука, которая официально «не в сети», всё-таки как-то откликалась. Ну что ж, держи несколько способов, как обойти эту хуйню, как настоящий гандон-разработчик.

Первый способ — накинуть сверху плёнку. Самый простой и тупой, как валенок. Берёшь прозрачную вьюху (UIView), накрываешь ею свою нерабочую кнопку или вью, и ловишь тапы уже по этой плёнке.

let overlay = UIView(frame: targetView.bounds)
overlay.isUserInteractionEnabled = true
targetView.addSubview(overlay)
let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
overlay.addGestureRecognizer(tapRecognizer)

Получается этакий подставной слушатель, который кричит: «Эй, система, я тут! Тычь в меня!», пока оригинальная вьюха притворяется мёртвой. Хитрая жопа, но работает.

Второй способ — магия hitTest. Это уже для тех, кто любит покопаться в кишках. Создаёшь свою кастомную вьюху и переопределяешь этот метод.

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    let hitView = super.hitTest(point, with: event)
    // Возвращаем nil для себя, чтобы события прошли "сквозь" эту вью
    return hitView == self ? nil : hitView
}

Суть в чём? Ты говоришь системе: «Знаешь что, когда ты ищешь, куда попали, и находишь меня — просто сделай вид, что меня нет. Иди искать дальше, вон там, подо мной, что-то интересное лежит». Событие пролетает сквозь тебя, как пуля сквозь говно, и попадает в то, что ниже. Ёперный театр, но иногда это единственный выход.

Третий способ — для кнопок, которые просто стесняются. Если у тебя UIControl (кнопка, свитч, слайдер), а он выключен, можно просто сымитировать нажатие программно, без всяких жестов.

button.sendActions(for: .touchUpInside)

Крикнул на неё — и она, блядь, сработала, как будто её ткнули. Прям как в том анекдоте: «Я не нажимал, это оно само!».

Но запомни главное, чувак: все эти финты ушами — это костыли, ебать мои старые костыли! Если вьюха по задумке должна отзываться на тап — включай ей isUserInteractionEnabled = true и не выёбывайся. А эти трюки — для особых, ебучьих случаев, когда архитектура проекта уже напоминает свалку и переделывать всё — терпения ноль ебать. Используй с умом, а то так и до багов, от которых волосы дыбом встанут, недалеко.