UIButton里面的视图有一个uitapgesturerecnizer

时间:2021-07-25 02:55:58

I have view with a UITapGestureRecognizer. So when I tap on the view another view appears above this view. This new view has three buttons. When I now press on one of these buttons I don't get the buttons action, I only get the tap gesture action. So I'm not able to use these buttons anymore. What can I do to get the events through to these buttons? The weird thing is that the buttons still get highlighted.

我有一个完整的视角。当我点击视图时,另一个视图出现在这个视图之上。这个新视图有三个按钮。当我现在按下其中一个按钮时,我没有得到按钮动作,我只有点击手势动作。我不能再用这些按钮了。我要怎么做才能让事件通过这些按钮?奇怪的是按钮仍然被突出显示。

I can't just remove the UITapGestureRecognizer after I received it's tap. Because with it the new view can also be removed. Means I want a behavior like the fullscreen vide controls.

我不能在我收到水龙头后就把UITapGestureRecognizer移除。因为有了它,新的视图也可以被删除。意思是我想要一个像全屏幕vide控件那样的行为。

11 个解决方案

#1


235  

You can set your controller or view (whichever creates the gesture recognizer) as the delegate of the UITapGestureRecognizer. Then in the delegate you can implement -gestureRecognizer:shouldReceiveTouch:. In your implementation you can test if the touch belongs to your new subview, and if it does, instruct the gesture recognizer to ignore it. Something like the following:

您可以将您的控制器或视图(创建手势识别器的那个)设置为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
}

#2


150  

As a follow up to Casey's follow up to Kevin Ballard's answer:

接下来是凯西对凯文·巴拉德的回答:

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

This basically makes all user input types of controls like buttons, sliders, etc. work

这基本上使所有用户输入类型的控件(如按钮、滑块等)都能工作

#3


91  

Found this answer here: link

在这里找到了答案:链接

You can also use

您还可以使用

tapRecognizer.cancelsTouchesInView = NO;

Which prevents the tap recognizer to be the only one to catch all the taps

是什么阻止了水龙头识别器成为唯一一个能抓住所有水龙头的

UPDATE - Michael mentioned the link to the documentation describing this property: cancelsTouchesInView

更新—Michael提到了描述此属性的文档的链接:cancelsTouchesInView。

#4


68  

As a follow up to Kevin Ballard's answer, I had this same problem and ended up using this code:

作为对Kevin Ballard的回答的跟进,我遇到了同样的问题,最后使用了以下代码:

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

It has the same effect but this will work on any UIButton at any view depth (my UIButton was several views deep and the UIGestureRecognizer's delegate didn't have a reference to it.)

它有同样的效果,但是它可以作用于任何UIButton在任何视图深度(我的UIButton有几个视图深度UIGestureRecognizer的委托没有对它的引用)

#5


7  

Found another way to do it from here. It detects the touch whether inside each button or not.

找到了另一种方法。它检测每个按钮内部的触摸。

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

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

#6


7  

In iOS 6.0 and later, default control actions prevent overlapping gesture recognizer behavior. For example, the default action for a button is a single tap. If you have a single tap gesture recognizer attached to a button’s parent view, and the user taps the button, then the button’s action method receives the touch event instead of the gesture recognizer. This applies only to gesture recognition that overlaps the default action for a control, which includes:.....

在ios6.0和更高版本中,默认控制动作可以防止手势识别器的重叠行为。例如,按钮的默认操作是一次点击。如果在按钮的父视图上附加了一个轻击手势识别器,并且用户轻击按钮,那么按钮的操作方法将接收触摸事件而不是手势识别器。这只适用于与控件的默认动作重叠的手势识别,其中包括:

From Apple's API doc

从苹果的API文档

#7


6  

These answers were incomplete. I had to read multiple posts as to how to use this boolean operation.

这些答案都是不完整的。我必须阅读多篇关于如何使用布尔运算的文章。

In your *.h file add this

在你的*。h文件添加这个

@interface v1ViewController : UIViewController <UIGestureRecognizerDelegate>

In your *.m file add this

在你的*。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


3  

Here's the swift version of Kevin Ballard answer that worked for me:

以下是凯文·巴拉德对我的迅速回答:

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

#9


1  

You can stop the UITapGestureRecognizer from cancelling other events (such as the tap on your button) by setting the following boolean:

您可以通过设置以下布尔值来阻止UITapGestureRecognizer取消其他事件(例如单击您的按钮):

    [tapRecognizer setCancelsTouchesInView:NO];

#10


1  

If your scenario is like this:

You have a simple view and some UIButtons,UITextField controls added as subviews to that view. Now you want to dismiss the keyboard when you touch anywhere else on the view except on the controls(subviews you added)

您有一个简单的视图和一些uibutton,UITextField控件添加为该视图的子视图。现在,除了控件(添加的子视图)之外,您还需要在视图上的其他地方触摸键盘

Then Solution is:

Add the following method to your XYZViewController.m(which has your view)

向XYZViewController添加以下方法。(你的观点)

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

#11


1  

Optimizing @cdasher's answer, you get

优化@cdasher的答案,你得到

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

#1


235  

You can set your controller or view (whichever creates the gesture recognizer) as the delegate of the UITapGestureRecognizer. Then in the delegate you can implement -gestureRecognizer:shouldReceiveTouch:. In your implementation you can test if the touch belongs to your new subview, and if it does, instruct the gesture recognizer to ignore it. Something like the following:

您可以将您的控制器或视图(创建手势识别器的那个)设置为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
}

#2


150  

As a follow up to Casey's follow up to Kevin Ballard's answer:

接下来是凯西对凯文·巴拉德的回答:

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

This basically makes all user input types of controls like buttons, sliders, etc. work

这基本上使所有用户输入类型的控件(如按钮、滑块等)都能工作

#3


91  

Found this answer here: link

在这里找到了答案:链接

You can also use

您还可以使用

tapRecognizer.cancelsTouchesInView = NO;

Which prevents the tap recognizer to be the only one to catch all the taps

是什么阻止了水龙头识别器成为唯一一个能抓住所有水龙头的

UPDATE - Michael mentioned the link to the documentation describing this property: cancelsTouchesInView

更新—Michael提到了描述此属性的文档的链接:cancelsTouchesInView。

#4


68  

As a follow up to Kevin Ballard's answer, I had this same problem and ended up using this code:

作为对Kevin Ballard的回答的跟进,我遇到了同样的问题,最后使用了以下代码:

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

It has the same effect but this will work on any UIButton at any view depth (my UIButton was several views deep and the UIGestureRecognizer's delegate didn't have a reference to it.)

它有同样的效果,但是它可以作用于任何UIButton在任何视图深度(我的UIButton有几个视图深度UIGestureRecognizer的委托没有对它的引用)

#5


7  

Found another way to do it from here. It detects the touch whether inside each button or not.

找到了另一种方法。它检测每个按钮内部的触摸。

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

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

#6


7  

In iOS 6.0 and later, default control actions prevent overlapping gesture recognizer behavior. For example, the default action for a button is a single tap. If you have a single tap gesture recognizer attached to a button’s parent view, and the user taps the button, then the button’s action method receives the touch event instead of the gesture recognizer. This applies only to gesture recognition that overlaps the default action for a control, which includes:.....

在ios6.0和更高版本中,默认控制动作可以防止手势识别器的重叠行为。例如,按钮的默认操作是一次点击。如果在按钮的父视图上附加了一个轻击手势识别器,并且用户轻击按钮,那么按钮的操作方法将接收触摸事件而不是手势识别器。这只适用于与控件的默认动作重叠的手势识别,其中包括:

From Apple's API doc

从苹果的API文档

#7


6  

These answers were incomplete. I had to read multiple posts as to how to use this boolean operation.

这些答案都是不完整的。我必须阅读多篇关于如何使用布尔运算的文章。

In your *.h file add this

在你的*。h文件添加这个

@interface v1ViewController : UIViewController <UIGestureRecognizerDelegate>

In your *.m file add this

在你的*。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


3  

Here's the swift version of Kevin Ballard answer that worked for me:

以下是凯文·巴拉德对我的迅速回答:

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

#9


1  

You can stop the UITapGestureRecognizer from cancelling other events (such as the tap on your button) by setting the following boolean:

您可以通过设置以下布尔值来阻止UITapGestureRecognizer取消其他事件(例如单击您的按钮):

    [tapRecognizer setCancelsTouchesInView:NO];

#10


1  

If your scenario is like this:

You have a simple view and some UIButtons,UITextField controls added as subviews to that view. Now you want to dismiss the keyboard when you touch anywhere else on the view except on the controls(subviews you added)

您有一个简单的视图和一些uibutton,UITextField控件添加为该视图的子视图。现在,除了控件(添加的子视图)之外,您还需要在视图上的其他地方触摸键盘

Then Solution is:

Add the following method to your XYZViewController.m(which has your view)

向XYZViewController添加以下方法。(你的观点)

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

#11


1  

Optimizing @cdasher's answer, you get

优化@cdasher的答案,你得到

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