UIButton внутри представления, которое имеет UITapGestureRecognizer

184

Я имею представление с UITapGestureRecognizer. Поэтому, когда я нажимаю на вид, над этим видом появляется другой вид. Этот новый вид имеет три кнопки. Когда я теперь нажимаю на одну из этих кнопок, я не получаю действие кнопок, я только получаю действие жеста касания. Поэтому я больше не могу использовать эти кнопки. Что я могу сделать, чтобы донести события до этих кнопок? Странно то, что кнопки по-прежнему подсвечиваются.

Я не могу просто удалить UITapGestureRecognizer после того, как я получил его нажмите. Потому что с его помощью новый вид также может быть удален. Означает, что я хочу поведение как полноэкранные элементы управления видео .

V1ru8
источник

Ответы:

256

Вы можете установить свой контроллер или представление (в зависимости от того, что создает распознаватель жестов) в качестве делегата UITapGestureRecognizer. Тогда в делегате вы можете реализовать -gestureRecognizer:shouldReceiveTouch:. В своей реализации вы можете проверить, принадлежит ли касание вашему новому подпредставлению, и если это так, дать указание распознавателю жестов игнорировать его. Что-то вроде следующего:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    // test if our control subview is on-screen
    if (self.controlSubview.superview != nil) {
        if ([touch.view isDescendantOfView:self.controlSubview]) {
            // we touched our control surface
            return NO; // ignore the touch
        }
    }
    return YES; // handle the touch
}
Лили Баллард
источник
В моем заголовочном файле мой вид реализовал UIGestoreRegognizerDelegate, и в моем .mi я добавил ваш код выше. Метчик никогда не входит в этот метод, он идет прямо к моему обработчику. Любые идеи?
kmehta
1
@kmehta вы, скорее всего, забыли установить свойство делегата UIGestureRecognizer.
до
Может ли этот ответ быть обобщенным для обработки всех случаев, когда задействован IBAction?
Мартин Уикман
@Martin IBAction компилируется voidтак, чтобы не оставлять никакой информации во время выполнения для использования при обнаружении. Но то, что вы можете сделать, это пройтись по иерархии представлений, проверить UIControlи вернуться, NOесли вы найдете какие-либо элементы управления.
Лили Баллард
спасибо за это, это помогает мне. если ваша кнопка находится в UIImageView, убедитесь, что userInteractionEnabled для imageView установлено в YES.
james075
156

Как продолжение Кейси после ответа Кевина Балларда:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
        if ([touch.view isKindOfClass:[UIControl class]]) {
            // we touched a button, slider, or other UIControl
            return NO; // ignore the touch
        }
    return YES; // handle the touch
}

Это в основном заставляет работать все типы пользовательских элементов управления, такие как кнопки, ползунки и т. Д.

cdasher
источник
1
Это гибкое решение, которое может сопровождаться, setCancelsTouchesInView = NOчтобы не вызывать жест касания при взаимодействии с элементами управления. Однако вы можете написать это лучше:return ![touch.view isKindOfClass:[UIControl class]];
griga13
Решение Swift 4+: возвращайтесь! (Touch.view - это UIControl)
nteissler
103

Нашел ответ здесь: ссылка

Вы также можете использовать

tapRecognizer.cancelsTouchesInView = NO;

Что мешает распознавателю крана быть единственным, чтобы поймать все крана

ОБНОВЛЕНИЕ - Майкл упомянул ссылку на документацию, описывающую это свойство: cancellsTouchesInView

ejazz
источник
8
Это должен быть принятый ответ ИМО. Это позволяет каждому подпредставлению обрабатывать касание самостоятельно и предотвращает «кражу» касания представлением, к которому прикреплен табулятор распознавания. Нет необходимости реализовывать делегат, если все, что вы хотите сделать, это сделать представление кликабельным (подать в отставку первого респондента / спрятать клавиатуру в текстовых полях и т. Д.) .. потрясающе!
EeKay
4
Это определенно должен быть принятый ответ. Этот ответ заставил меня внимательно прочитать документацию Apple , которая ясно дает понять, что распознаватель жестов будет препятствовать получению распознанными событиями подпредставлений, если вы этого не сделаете.
Михаэль ван дер Вестхайзен
1
Раньше это работало, но теперь это не работает для меня .. возможно, потому что у меня есть scrollView под кнопкой? Я должен был реализовать делегата, как в ответах выше.
Киссбург
7
Немного поэкспериментировав, я заметил, что это будет работать только в том случае, если представление, которое содержит распознаватель жестов, является родственным элементом UIControl, и не будет, если представление является родителем UIControl.
Киссбург
6
На самом деле не работает, как задумано ... ДА, это предотвращает распознавание касаний, чтобы съесть событие на UIControl. Но он все еще запускает действие распознавателя, которое запускает действие 2 одновременно.
Тек Инь