web-dev-qa-db-ja.com

UITapGestureRecognizerを持つビュー内のUIButton

UITapGestureRecognizerのビューがあります。そのため、ビューをタップすると、このビューの上に別のビューが表示されます。この新しいビューには3つのボタンがあります。これらのボタンのいずれかを押すと、ボタンアクションが表示されず、タップジェスチャアクションのみが表示されます。そのため、これらのボタンはもう使用できません。これらのボタンにイベントを送信するにはどうすればよいですか?奇妙なことは、ボタンがまだ強調表示されることです。

UITapGestureRecognizerをタップした後に削除することはできません。これにより、新しいビューも削除できるためです。 フルスクリーンビデオコントロールのような動作が必要なことを意味します。

177
V1ru8

コントローラーまたはビュー(ジェスチャー認識機能を作成する方)を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
}
250
Lily Ballard

ケヴィン・バラードの答えへのケーシーのフォローアップのフォローアップとして:

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

これにより、基本的にボタン、スライダーなどのすべてのユーザー入力タイプのコントロールが機能します。

155
cdasher

ここでこの答えを見つけました: link

使用することもできます

tapRecognizer.cancelsTouchesInView = NO;

これにより、タップ認識エンジンがすべてのタップをキャッチする唯一の存在になりません

更新- Michael このプロパティを説明するドキュメントへのリンクに言及しました: cancelsTouchesInView

100
ejazz

Kevin Ballardの回答のフォローアップとして、私はこの同じ問題を抱えていて、このコードを使用することになりました。

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

同じ効果がありますが、これは任意のビュー深度の任意のUIButtonで機能します(私のUIButtonはいくつかのビューの深さで、UIGestureRecognizerのデリゲートはそれへの参照を持っていませんでした。)

71
Casey

IOS 6.0以降では、デフォルトのコントロールアクションにより、ジェスチャレコグナイザーの動作の重複が防止されます。たとえば、ボタンのデフォルトアクションはシングルタップです。ボタンの親ビューにアタッチされたシングルタップジェスチャレコグナイザーがあり、ユーザーがボタンをタップすると、ボタンのアクションメソッドはジェスチャレコグナイザーの代わりにタッチイベントを受け取ります。これは、コントロールのデフォルトアクションと重複するジェスチャ認識にのみ適用されます。

AppleのAPIドキュメントから

10
Jagie

これらの答えは不完全でした。このブール演算の使用方法については、複数の投稿を読む必要がありました。

* .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 ...");

}
8
Sam B

here から別の方法を見つけました。各ボタンの中かどうかに関係なく、タッチを検出します。

(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]);
}
7
MindMirror

リリー・バラードの答え のSwiftバージョンは次のとおりです。

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if (scrollView.superview != nil) {
        if ((touch.view?.isDescendantOfView(scrollView)) != nil) { return false }
    }
    return true
}
3
John Riselvato

Cdasherの答えを最適化すると、

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
       shouldReceiveTouch:(UITouch *)touch 
{
    return ![touch.view isKindOfClass:[UIControl class]];
}
1
Clay Bridges

シナリオが次のような場合:

シンプルなビューと、そのビューにサブビューとして追加されたUIButton、UITextFieldコントロールがあります。ここで、コントロール(追加したサブビュー)以外のビュー上の任意の場所をタッチすると、キーボードを閉じます。

解決策は次のとおりです。

XYZViewController.m(ビューがあります)に次のメソッドを追加します

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

次のブール値を設定することにより、UITapGestureRecognizerが他のイベント(ボタンのタップなど)をキャンセルしないようにすることができます。

    [tapRecognizer setCancelsTouchesInView:NO];
1