UIButton在具有UITapGestureRecognizer的视图中

V1r*_*ru8 180 iphone cocoa-touch objective-c ios uitapgesturerecognizer

我有一个观点UITapGestureRecognizer.因此,当我点击视图时,此视图上方会出现另一个视图.这个新视图有三个按钮.当我现在按下其中一个按钮时,我没有按下按钮动作,我只得到轻击手势动作.所以我不能再使用这些按钮了.我该怎么做才能将事件传递给这些按钮?奇怪的是按钮仍然突出显示.

我收到它后,我不能删除UITapGestureRecognizer.因为有了它,也可以删除新视图.意味着我想要像全屏视频控件一样的行为.

Lil*_*ard 254

您可以将控制器或视图(以创建手势识别器为准)设置为代理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
}
Run Code Online (Sandbox Code Playgroud)


cda*_*her 155

作为凯西跟随凯文巴拉德回答的后续行动:

- (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
}
Run Code Online (Sandbox Code Playgroud)

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

  • Swift 4+解决方案:返回!(touch.view是UIControl) (2认同)

eja*_*azz 103

在这里找到这个答案:链接

你也可以使用

tapRecognizer.cancelsTouchesInView = NO;
Run Code Online (Sandbox Code Playgroud)

这可以防止水龙头识别器成为唯一能够捕获所有水龙头的人

更新 - 迈克尔提到了描述此属性的文档的链接:cancelsTouchesInView

  • 这应该是IMO接受的答案.这使得每个子视图都可以自己处理点击,并通过"劫持"点击来防止附加了tabrecognizer的视图.如果您想要做的就是使视图可点击(在第一个响应者身上/在文本字段上隐藏键盘等),则无需实现委托.真棒! (8认同)
  • 稍微试验一下后,我注意到只有包含手势识别器的视图是UIControl的兄弟,这才会起作用,如果视图是UIControl的父节点,则不会. (7认同)
  • 没有按预期工作......是的,它阻止了点击识别器在UIControl上吃事件.但它仍然运行识别器动作,同时运行2动作. (5认同)
  • 这绝对应该是公认的答案.这个答案让我正确阅读了[Apple文档](http://developer.apple.com/library/ios/#documentation/UIKit/Reference/UIGestureRecognizer_Class/Reference/Reference.html),这清楚地表明了手势识别器将阻止子视图获取已识别的事件_unless_您执行此操作. (4认同)

Cas*_*sey 71

作为Kevin Ballard的回答,我遇到了同样的问题并最终使用了这段代码:

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

它具有相同的效果,但这适用于任何视图深度的任何UIButton(我的UIButton有几个视图深,而UIGestureRecognizer的委托没有对它的引用.)

  • 不想在这里成为一个鸡巴,但它确实是,不.请使用Cocoa约定.TRUE/FALSE/NULL用于CoreFoundation-Layer. (6认同)
  • 它可能看起来很主观,但经过一段时间的Cocoa编程,你真的进入了语义更精确的代码流......现在,经过多年的Objective-C,"TRUE"似乎真的错了,因为它与"隐藏"非常不匹配好. (2认同)

Jag*_*gie 10

在iOS 6.0及更高版本中,默认控制操作可防止重叠手势识别器行为.例如,按钮的默认操作是单击.如果您将单击手势识别器附加到按钮的父视图,并且用户点击该按钮,则该按钮的操作方法将接收触摸事件而不是手势识别器.这仅适用于与控件的默认操作重叠的手势识别,其中包括:.....

来自Apple的API文档


Sam*_*m B 8

这些答案都不完整.我必须阅读有关如何使用此布尔操作的多个帖子.

在*.h文件中添加此项

@interface v1ViewController : UIViewController <UIGestureRecognizerDelegate>
Run Code Online (Sandbox Code Playgroud)

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

}
Run Code Online (Sandbox Code Playgroud)


小智 7

这里找到了另一种方法.它会检测每个按钮内部是否有触摸.

(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]);
}
Run Code Online (Sandbox Code Playgroud)


Shr*_*Pal 7

斯威夫特 5

带有轻触手势的超级视图上的按钮

 func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    if let _ = touch.view as? UIButton { return false }
    return true
}
Run Code Online (Sandbox Code Playgroud)

在我的情况下,实现hitTest对我有用。我有带按钮的集合视图

该方法通过调用point(inside:with:)每个子视图的方法来遍历视图层次结构,以确定哪个子视图应该接收触摸事件。如果point(inside:with:)返回 true,则类似地遍历子视图的层次结构,直到找到包含指定点的最前面的视图。

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    guard isUserInteractionEnabled else { return nil }

    guard !isHidden else { return nil }

    guard alpha >= 0.01 else { return nil }

    guard self.point(inside: point, with: event) else { return nil }

    for eachImageCell in collectionView.visibleCells {
        for eachImageButton in eachImageCell.subviews {
            if let crossButton = eachImageButton as? UIButton {
                if crossButton.point(inside: convert(point, to: crossButton), with: event) {
                    return crossButton
                }
            }
        }
    }
    return super.hitTest(point, with: event)
}
Run Code Online (Sandbox Code Playgroud)