Дії розпізнавача жестів та кнопок


99

У мене є ієрархія перегляду, яка виглядає приблизно так:

UIView (A)
UIView > UIImageView
UIView > UIView (B)
UIView > UIView (B) > Rounded Rect Button
UIView > UIView (B) > UIImageView
UIView > UIView (B) > UILabel

Я додав розпізнавальник жестів до мого UIView (B). Проблема, з якою я стикаюсь, полягає в тому, що я не отримую жодних дій для кнопки "Закруглена прямота", яка знаходиться всередині UIView (B). Розпізнавальник жестів SingleTap фіксує / переосмислює подію Touch Up Inside кнопки.

Як я можу змусити це працювати? Я думав, що ієрархія ланцюга відповідей переконається, що подію натискання кнопки буде надано перевагу, і вона буде спрацьовувати! Що я пропускаю?

Ось кілька пов'язаних кодів:

#pragma mark -
#pragma mark View lifecycle (Gesture recognizer setup)

- (void)viewDidLoad {
    [super viewDidLoad];

    // double tap gesture recognizer
    UITapGestureRecognizer *dtapGestureRecognize = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(doubleTapGestureRecognizer:)];
    dtapGestureRecognize.delegate = self;
    dtapGestureRecognize.numberOfTapsRequired = 2;
    [self.viewB addGestureRecognizer:dtapGestureRecognize];

    // single tap gesture recognizer
    UITapGestureRecognizer *tapGestureRecognize = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapGestureRecognizer:)];
    tapGestureRecognize.delegate = self;
    tapGestureRecognize.numberOfTapsRequired = 1;
    [tapGestureRecognize requireGestureRecognizerToFail:dtapGestureRecognize];
    [self.viewB addGestureRecognizer:tapGestureRecognize];

    // add gesture recodgnizer to the grid view to start the edit mode
    UILongPressGestureRecognizer *pahGestureRecognizer = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(longPressGestureRecognizerStateChanged:)];
    pahGestureRecognizer.delegate = self;
    pahGestureRecognizer.minimumPressDuration = 0.5;
    [self.viewB addGestureRecognizer:pahGestureRecognizer];

    [dtapGestureRecognize release];
    [tapGestureRecognize release];
    [pahGestureRecognizer release];
}

#pragma mark -
#pragma mark Button actions

- (IBAction)buttonTouchUpInside:(id)sender {
    NSLog(@"%s, %@", __FUNCTION__, sender);
}

#pragma mark -
#pragma mark Gesture recognizer actions


- (void)singleTapGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
    NSLog(@"%s", __FUNCTION__);
}

- (void)doubleTapGestureRecognizer:(UIGestureRecognizer *)gestureRecognizer {
    NSLog(@"%s", __FUNCTION__);
}

- (void)longPressGestureRecognizerStateChanged:(UIGestureRecognizer *)gestureRecognizer {

    switch (gestureRecognizer.state) {

        case UIGestureRecognizerStateEnded: {
            NSLog(@"%s", __FUNCTION__);

            break;
        }
        default:
            break;
    }
}

Найпростіший спосіб встановити cancelsTouchesInView = брехня
— Bagusflyer

Відповіді:


176

У методі "shouldReceiveTouch" слід додати умову, яка поверне "НІ", якщо натискання кнопки.

Це на прикладі яблучного SimpleGestureRecognizers .

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

    // Disallow recognition of tap gestures in the segmented control.
    if ((touch.view == yourButton)) {//change it to your condition
        return NO;
    }
    return YES;
}

сподіваюся, що це допоможе

Редагувати

Як зазначив Даніель, ви повинні відповідати, щоб UIGestureRecognizerDelegateце працювало.

шані


1
Ах !!! Так, я забув про цей -gestureRecognizer: shouldReceiveTouch: метод. Дякую, що вказали на мене в правильному напрямку. Хоча це і вирішує мою проблему, але я досі не знаю, чому ієрархія респондентів не працює в цьому випадку. Це, мабуть, повинно, але Apple цим не займається.
— Мустафа

2
Поведінка UIGestureRecognizer чітко описується як окрема від "нормальної" ланцюга реагування. Це дизайнерське рішення від Apple.
— Sylvain G.

11
Не забудьте відповідати протоколу UIGestureRecognizerDelegate та встановити делегат UIGestureRecognizer до цього об'єкта.
— Даніель

2
Для ширшого використання розглянемо якийсь варіант із тестових статей Рамеша або flypig. У моєму випадку, наприклад, я закінчився рядком: if ( [touch.view isKindOfClass:[UIControl class]] || [[touch.view superview] isKindOfClass:[UITableViewCell class]] ) {... Зауважте, що комірки tableview "торкаються" у своєму contentView, який є членом приватного класу, тому ми перевіряємо замість цього класу нагляду.
— clozach

Дякую за відповідь! У моєму випадку я зіткнувся з тією ж проблемою, але я виявив її лише до тих пір, поки не перевірив фактичний пристрій. Запуск програми в тренажері без використання UIGestureDelegate, як зазначено у цій відповіді, працював так, як очікувалося, хоча й неправильно.
— Луїс Артола

51

У мене також була така ж проблема, тоді я спробував

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

    if ([touch.view isKindOfClass:[UIButton class]]) {      //change it to your condition
        return NO;
    }
    return YES;
}

Зараз він ідеально працює .........


4
я лише пропустивmyGestureRecognizer.delegate = self;
— zero3nna

20

Взагалі ми використовуємо метод делегування нижче, щоб уникнути дотику до всіх видів UIControls:

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

Примітка: НЕ робіть цю перевірку (перевірте тип класу prepoznaє.вигляд) gestureRecognizerShouldBegin, він не працюватиме.


11

Ось версія Swift 3.0 :

extension UIViewController: UIGestureRecognizerDelegate {

public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    if touch.view is UIButton {
        return false
    }
    return true
}

Не забудьте:

Make your tapper object delegate to self (e.g: tapper.delegate = self)


6

Ось версія Swift:

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if (touch.view!.isKindOfClass(UIButton)) {
        return false
    }
    return true
}

Не забудьте:

  1. Зробіть, щоб ви відповідали класу UIGestureRecognizerDelegate
  2. Зробіть свій об'єкт конусність делегат самостійно (наприклад: tapper.delegate = self)

5

Найкраще рішення - на мою думку, використовуючи фрагмент коду нижче:

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    CGPoint touchLocation = [touch locationInView:self.view];
    return !CGRectContainsPoint(self.menuButton.frame, touchLocation);
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.