ジェスチャー認識機能とボタンアクション


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)内にあるRounded Rect Buttonのアクションを取得できないことです。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 = falseを設定することです
Bagusflyer

回答:


176

「shouldReceiveTouch」メソッドでは、ボタンがタッチされた場合にNOを返す条件を追加する必要があります。

これはアップルの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年

11
UIGestureRecognizerDelegateプロトコルに準拠し、UIGestureRecognizerのデリゲートをそのオブジェクトに設定することを忘れないでください。
ダニエル

2
より広く使用するために、Rameshまたはflypigのテスト節のバリアントを検討してください。たとえば、私の場合、次の行で終わりました:if ( [touch.view isKindOfClass:[UIControl class]] || [[touch.view superview] isKindOfClass:[UITableViewCell class]] ) {... tableviewセルは、プライベートクラスのメンバーであるcontentViewで「タッチ」されるので、代わりにスーパービューのクラスをチェックします。
clozach

答えてくれてありがとう!私の場合、同じ問題に遭遇しましたが、実際のデバイスでテストするまでしか発見できませんでした。この回答に示されているように、UIGestureDelegateを使用せずにシミュレーターでアプリを実行すると、正しくはありましたが期待どおりに機能しました。
Luis Artola 2013

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 2013年

20

一般的に言えば、以下のデリゲートメソッドを使用して、あらゆる種類のUIControlのタッチを回避します。

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

注:このチェック(recognizer.viewクラスタイプをチェック)を行わないでください。ジェスチャーのRecognizerShouldBeginは機能しません。


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);
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.