手势识别器和按钮操作

发布于 2024-10-14 10:18:57 字数 2555 浏览 8 评论 0原文

我有一个看起来像这样的视图层次结构:

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) 内的圆角矩形按钮执行任何操作。 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;
    }
}

I have a view hierarchy that looks something like this:

UIView (A)
UIView > UIImageView
UIView > UIView (B)
UIView > UIView (B) > Rounded Rect Button
UIView > UIView (B) > UIImageView
UIView > UIView (B) > UILabel

I've attached gesture recognizer(s) to my UIView (B). The problem that i'm facing is that i don't get any actions for the Rounded Rect Button which is inside the UIView (B). The singleTap gesture recognizer captures/overrides the button's Touch Up Inside event.

How can i make it work? I thought that the responder chain hierarchy will make sure that the button touch event will be given preference, and it WILL get triggered! What am i missing?

Here's some related code:

#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;
    }
}

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

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

发布评论

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

评论(9

别挽留 2024-10-21 10:18:57

在“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;
}

希望它会有所帮助

编辑

正如 Daniel 指出的,您必须遵守 UIGestureRecognizerDelegate 才能正常工作。

沙尼

In the "shouldReceiveTouch" method you should add a condition that will return NO if the touch is in the button.

This is from apple SimpleGestureRecognizers example.

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

hope it will help

Edit

As Daniel noted you must conform to UIGestureRecognizerDelegate for it to work.

shani

当梦初醒 2024-10-21 10:18:57

我也遇到了同样的问题,然后我尝试了

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{

    if ([touch.view isKindOfClass:[UIButton class]]) {      //change it to your condition
        return NO;
    }
    return YES;
}

它现在工作正常..............

I also had the same problem , then i tried with

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{

    if ([touch.view isKindOfClass:[UIButton class]]) {      //change it to your condition
        return NO;
    }
    return YES;
}

It is working now perfectly.........

鹿港巷口少年归 2024-10-21 10:18:57

一般来说,我们使用下面的委托方法来避免各种UIControls中的触摸:

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

注意:不要对gestureRecognizerShouldBegin进行此检查(检查recognizer.view类类型),它不会起作用。

Generally speaking, we use below delegate method to avoid the touch in all kinds of UIControls:

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

Note: DO NOT do this check (check the recognizer.view class type) the gestureRecognizerShouldBegin, it won't work.

夏末 2024-10-21 10:18:57

这是一个 Swift 3.0 版本:

extension UIViewController: UIGestureRecognizerDelegate {

public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    if touch.view is UIButton {
        return false
    }
    return true
}

不要忘记:

让你的 Tapper 对象委托给 self(例如:tapper.delegate = self)

Here is a Swift 3.0 version:

extension UIViewController: UIGestureRecognizerDelegate {

public func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    if touch.view is UIButton {
        return false
    }
    return true
}

Don't forget to:

Make your tapper object delegate to self (e.g: tapper.delegate = self)

网名女生简单气质 2024-10-21 10:18:57

在我看来,最好的解决方案是使用下面的代码片段:

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    CGPoint touchLocation = [touch locationInView:self.view];
    return !CGRectContainsPoint(self.menuButton.frame, touchLocation);
}

The best solution is to my mind using code snippet below:

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
    CGPoint touchLocation = [touch locationInView:self.view];
    return !CGRectContainsPoint(self.menuButton.frame, touchLocation);
}
谁许谁一生繁华 2024-10-21 10:18:57

这是一个 Swift 版本:

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if (touch.view!.isKindOfClass(UIButton)) {
        return false
    }
    return true
}

不要忘记:

  1. 让你的类符合 UIGestureRecognizerDelegate
  2. 让你的 Tapper 对象委托给 self(例如:tapper.delegate = self

Here is a Swift version:

func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldReceiveTouch touch: UITouch) -> Bool {
    if (touch.view!.isKindOfClass(UIButton)) {
        return false
    }
    return true
}

Don't forget to:

  1. Make you class conform to UIGestureRecognizerDelegate
  2. Make your tapper object delegate to self (e.g: tapper.delegate = self)
陌伤浅笑 2024-10-21 10:18:57

对于委托内的 Swift 5,您只需添加:

return (touch.view is UIButton) ? false : true

for Swift 5 inside the delegate you can just add:

return (touch.view is UIButton) ? false : true
月寒剑心 2024-10-21 10:18:57

Vivienne 答案的 Swift 版本:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    let location = touch.location(in: view)
    return !someView.frame.contains(location)
}

Swift version of Vivienne answer:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    let location = touch.location(in: view)
    return !someView.frame.contains(location)
}
虫児飞 2024-10-21 10:18:57

我的情况如下:

UIView (with tap gesture)
├-> UIView (named "textFieldView")
    ├-> UIControl
    ├-> UITextField
    ├-> UIView (over the textField, with a tap gesture)

╭──────────────────────────────╮
│ ╭──────────────────────────╮ │
│ │ ╭──╮  ┌╴╶╴╶╴╶╴╶╴╶╴╶╴╶╴╶┐ │ │
│ │ ╰──╯  └╴╶╴╶╴╶╴╶╴╶╴╶╴╶╴╶┘ │ │
│ ╰──────────────────────────╯ │
└──────────────────────────────┘

上部 UIView 上的 tapGesture 导致与 UIControl 目标发生冲突。如果目标是使用 touchDown 设置的(但未调用 touchUpInside),或者如果我将继承从 UIControl 更改为 < code>UIButton,同时保持事件 touchUpInside 上的目标设置。

我要做的就是解决这个问题:
上视图被设置为其点击手势的代表。
函数 funcgestureRecognizer(_gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool 的实现(在上层 UIView 中)如下所示:

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    let touchLocationRelatedToTextFieldView = touch.location(in: textFieldView)
    return textFieldView.frame.contains(touchLocationRelatedToTextFieldView) == false
}

通过实现该委托函数,我现在可以将 UIControl 和目标设置保留在 touchUpInside 上! :)

My case was the following :

UIView (with tap gesture)
├-> UIView (named "textFieldView")
    ├-> UIControl
    ├-> UITextField
    ├-> UIView (over the textField, with a tap gesture)

╭──────────────────────────────╮
│ ╭──────────────────────────╮ │
│ │ ╭──╮  ┌╴╶╴╶╴╶╴╶╴╶╴╶╴╶╴╶┐ │ │
│ │ ╰──╯  └╴╶╴╶╴╶╴╶╴╶╴╶╴╶╴╶┘ │ │
│ ╰──────────────────────────╯ │
└──────────────────────────────┘

The tapGesture on the upper UIView was causing a conflict with the UIControl target. The target was called if the target was setup with touchDown (but not called for touchUpInside) or if I was changing the inheritance from UIControl to UIButton while keeping the target setup on event touchUpInside.

What I do to solve that is :
upper view is setup as delegate of its tap gesture.
Function func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool is implemented (in upper UIView) like that :

func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool {
    let touchLocationRelatedToTextFieldView = touch.location(in: textFieldView)
    return textFieldView.frame.contains(touchLocationRelatedToTextFieldView) == false
}

With that delegate function implemented I'm now able to keep my UIControl and the target setup on touchUpInside! :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文