UIButton внутри представления, которое имеет UITapGestureRecognizer - PullRequest
175 голосов
/ 27 июля 2010

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

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

Ответы [ 11 ]

246 голосов
/ 28 июля 2010

Вы можете установить свой контроллер или представление (в зависимости от того, что создает распознаватель жестов) в качестве делегата 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
}
155 голосов
/ 05 сентября 2011

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

- (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
}

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

100 голосов
/ 17 января 2012

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

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

tapRecognizer.cancelsTouchesInView = NO;

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

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

71 голосов
/ 14 июля 2011

В ответ на ответ Кевина Балларда у меня возникла та же проблема, и в итоге я использовал этот код:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    if ([touch.view isKindOfClass:[UIButton class]]){
        return NO;
    }
    return YES;
}

Он имеет тот же эффект, но он будет работать на любом UIButton на любой глубине просмотра (мой UIButton имел несколько просмотров и делегат UIGestureRecognizer не имел на него ссылку.)

10 голосов
/ 20 ноября 2013

В iOS 6.0 и более поздних версиях действия по умолчанию предотвращают перекрывающиеся действия распознавателя жестов. Например, действие по умолчанию для кнопки - одно нажатие. Если к родительскому представлению кнопки подключен распознаватель жестов с одним касанием, а пользователь нажимает кнопку, метод действия кнопки получает событие касания вместо распознавателя жестов. Это относится только к распознаванию жестов, которое перекрывает действие по умолчанию для элемента управления, которое включает: .....

Из документа Apple API

8 голосов
/ 19 августа 2013

Эти ответы были неполными. Мне пришлось прочитать несколько сообщений о том, как использовать эту логическую операцию.

В вашем * .h файле добавьте это

@interface v1ViewController : UIViewController <UIGestureRecognizerDelegate>

В вашем * .m файле добавьте это

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {

    NSLog(@"went here ...");

    if ([touch.view isKindOfClass:[UIControl class]])
    {
        // we touched a button, slider, or other UIControl
        return NO; // ignore the touch
    }
    return YES; // handle the touch
}
- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.



    //tap gestrure
    UITapGestureRecognizer *tapGestRecog = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(screenTappedOnce)];
    [tapGestRecog setNumberOfTapsRequired:1];
    [self.view addGestureRecognizer:tapGestRecog];


// This line is very important. if You don't add it then your boolean operation will never get called
tapGestRecog.delegate = self;

}


-(IBAction) screenTappedOnce
{
    NSLog(@"screenTappedOnce ...");

}
7 голосов
/ 08 августа 2011

Нашел другой способ сделать это из здесь .Он обнаруживает касание, находится ли внутри каждой кнопки или нет.

(1) pointInside: withEvent: (2) locationInView:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer 
       shouldReceiveTouch:(UITouch *)touch {
    // Don't recognize taps in the buttons
    return (![self.button1 pointInside:[touch locationInView:self.button1] withEvent:nil] &&
            ![self.button2 pointInside:[touch locationInView:self.button2] withEvent:nil] &&
            ![self.button3 pointInside:[touch locationInView:self.button3] withEvent:nil]);
}
3 голосов
/ 02 июня 2016

Вот Swift-версия Ответ Лили Баллард , который мне помог:

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if (scrollView.superview != nil) {
        if ((touch.view?.isDescendantOfView(scrollView)) != nil) { return false }
    }
    return true
}
1 голос
/ 13 ноября 2015

Оптимизируя ответ cdasher, вы получаете

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
       shouldReceiveTouch:(UITouch *)touch 
{
    return ![touch.view isKindOfClass:[UIControl class]];
}
1 голос
/ 23 мая 2013

Если ваш сценарий выглядит следующим образом:

У вас есть простое представление и некоторые кнопки UIB, элементы управления UITextField добавляются в качестве подпредставлений для этого представления.Теперь вы хотите закрыть клавиатуру, когда вы касаетесь где-либо еще в представлении, кроме элементов управления (добавленных вами подпредставлений)

Тогда решение будет следующим:

Добавьте следующий метод к вашему XYZViewController.m (который имеет ваше мнение)

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.view endEditing:YES];
}
...