具有 UITapGestureRecognizer 的视图内的 UIButton

发布于 2024-09-11 06:23:59 字数 271 浏览 2 评论 0原文

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

我不能在收到 UITapGestureRecognizer 的点击后将其删除。因为有了它,新视图也可以被删除。意味着我想要一个类似全屏视频控件的行为

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

女中豪杰 2024-09-18 06:23:59

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

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:

- (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
}
青春有你 2024-09-18 06:23:59

作为凯西对凯文巴拉德答案的后续行动:

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

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

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

风为裳 2024-09-18 06:23:59

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

您还可以使用

tapRecognizer.cancelsTouchesInView = NO;

which防止点击识别器成为唯一一个捕获所有点击

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

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

此刻的回忆 2024-09-18 06:23:59

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

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

它具有相同的效果,但这适用于任何视图深度的任何 UIButton(我的 UIButton 是多个视图深度,而 UIGestureRecognizer 的委托没有)没有参考它。)

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

- (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.)

幽梦紫曦~ 2024-09-18 06:23:59

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

来自 Apple 的 API 文档

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:.....

From Apple's API doc

吲‖鸣 2024-09-18 06:23:59

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

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

}

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

In your *.h file add this

@interface v1ViewController : UIViewController <UIGestureRecognizerDelegate>

In your *.m file add this

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

}
七月上 2024-09-18 06:23:59

此处找到了另一种方法。它检测触摸是否在每个按钮内部。

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

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

(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]);
}
伪心 2024-09-18 06:23:59

带有 Tapgesture 的超级视图上的Swift 5

按钮

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

在我的例子中,实现 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)
}

Swift 5

Button on superview with tapgesture

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

In my case implementing hitTest worked for me. I had collection view with button

This method traverses the view hierarchy by calling the point(inside:with:) method of each subview to determine which subview should receive a touch event. If point(inside:with:) returns true, then the subview’s hierarchy is similarly traversed until the frontmost view containing the specified point is found.

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)
}
等数载,海棠开 2024-09-18 06:23:59

这是对我有用的 Lily Ballard 的答案 的 Swift 版本:

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

Here's the Swift version of Lily Ballard's 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
}
公布 2024-09-18 06:23:59

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

    [tapRecognizer setCancelsTouchesInView:NO];

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

    [tapRecognizer setCancelsTouchesInView:NO];
回梦 2024-09-18 06:23:59

如果您的场景是这样的:

您有一个简单的视图和一些 UIButtons、UITextField 控件作为子视图添加到该视图。现在,当您触摸视图上除控件(您添加的子视图)之外的任何其他位置时,您想关闭键盘

那么解决方案是:

将以下方法添加到您的 XYZViewController.m(其中有您的视图)

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

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)

Then Solution is:

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

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    [self.view endEditing:YES];
}
深者入戏 2024-09-18 06:23:59

优化cdasher的答案,你得到

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

Optimizing cdasher's answer, you get

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
       shouldReceiveTouch:(UITouch *)touch 
{
    return ![touch.view isKindOfClass:[UIControl class]];
}
另类 2024-09-18 06:23:59

另一种选择是将 UITapGestureRecognizer 附加到 UIButton 下方的某个子视图,而不是附加到主 viewController 视图

假设您有一个子视图 mySubView > 并且按钮堆叠在它上面,但不属于它。然后你将创建你的 tapGestureRecognizer 如下

var tapGetureRecognizer = UITapGestureRecognizer()
tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(theActionToBeTriggered))
    tapGestureRecognizer.numberOfTapsRequired = 1
    mySubView.addGestureRecognizer(tapGestureRecognizer)

Another option is to attach the UITapGestureRecognizer to some subView that is underneath the UIButton, instead of attaching to your main viewController view

Say you have a subView mySubView and teh buttons are stacked over it, but do not belong to it. Then you will create your tapGestureRecognizer as follows

var tapGetureRecognizer = UITapGestureRecognizer()
tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(theActionToBeTriggered))
    tapGestureRecognizer.numberOfTapsRequired = 1
    mySubView.addGestureRecognizer(tapGestureRecognizer)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文