Как исключить объект из responder chain?
Что проверяют
Различаете ли вы две вещи: hit-testing, который выбирает, кому достанется касание, и саму цепочку next, по которой необработанное событие идёт вверх. «Исключить объект» для касаний и для действий приходится разными способами. Следом часто просят написать view, которая пропускает касания сквозь себя.
Как отвечать
Механика такая: касание находит адресата через hitTest(_:with:): система спускается по иерархии и выбирает самую глубокую view под пальцем. Если та событие не обработала, оно поднимается по next: view, её superview, контроллер, окно, UIApplication, делегат приложения.
Способы под задачу:
- не получать касания:
isUserInteractionEnabled = false,isHidden = trueилиalphaменьше 0.01. Hit-testing такую view вместе с потомками пропускает, касание достаётся тому, что лежит под ней; - пропускать касания точечно: переопределить
hitTest(_:with:)и вернутьnil, когда попали в саму view, а не в её кнопки. Так делают прозрачный оверлей над рабочим контентом. Вариант попроще:point(inside:with:)возвращаетfalse; - не становиться first responder:
canBecomeFirstResponderвозвращаетfalse, у уже активного объекта вызываютresignFirstResponder(); - пропускать действия дальше: для экшенов с
nil-таргетом, команд меню иUIKeyCommandпереопределитьcanPerformAction(_:withSender:)и вернутьfalse, тогда поиск обработчика пойдёт к следующему звену; - в SwiftUI: модификатор
allowsHitTesting(false).
Отдельно про override var next: UIResponder? с return nil. Объект от этого из цепочки не выпадает и по-прежнему первым получает событие, зато всё, что выше, необработанных событий больше не видит. Это обрезка цепочки.
Где спотыкаются
Предлагают переопределить next как способ «исключить себя». На деле ломается доставка событий контроллеру и окну, а сам объект остаётся в игре.
Забывают, что isUserInteractionEnabled = false действует на всё поддерево. Выключили на контейнере, и перестали нажиматься кнопки внутри.
Путают касания и экшены. Касание идёт через hit-testing, а sendAction с nil-таргетом ищет обработчик по цепочке от first responder, и отключается это другими методами.