UITapGestureRecognizer 在子视图中阻止 UIButton 的触摸事件

Posted

技术标签:

【中文标题】UITapGestureRecognizer 在子视图中阻止 UIButton 的触摸事件【英文标题】:UITapGestureRecognizer blocks touch event for UIButton in subview 【发布时间】:2016-09-19 02:35:50 【问题描述】:

我相信我在使用 UITapGestureRecognizer 时遇到问题,因为在聊天室区域中点击时会关闭键盘,从而阻止或阻止对 previewCancelButton 的触摸。以下是我的相关代码:

BaseTemplateVC.m

- (void)addDismissKeyboardGesture 

    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(dismissKeyboard:)];
    tapGesture.cancelsTouchesInView = NO;
    tapGesture.delegate = self;
    self.view.tag = 111;
    [self.view addGestureRecognizer:tapGesture];


- (void) dismissKeyboard:(id)sender 
    UITapGestureRecognizer *gesture = sender;
    UIView *view = gesture.view;
    NSLog(@"%ld", (long)view.tag);
    [self.view endEditing:YES];

ChatroomVC.m

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


    //Disallow recognition of tap gestures in the segmented control.
    if (([touch.view isKindOfClass:[UIButton class]])) 
        NSLog(@"noooooooo");
        return NO;
    
    return YES;
    NSLog(@"yesssssss"); 

InputFunctionView.m

- (void)selectedSticker:(NSString *)stickerURLString 

    /* Sticker preview subview */
    stickerPreviewView = [[UIImageView alloc] initWithFrame:CGRectMake(0, -120, FrameWidth, 120)];
    stickerPreviewView.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.5f];
    stickerPreviewView.userInteractionEnabled = YES;
    [self addSubview:stickerPreviewView];
    [self bringSubviewToFront:stickerPreviewView];

    /* Initialise previewCancelButton */
    self.previewCancelButton = [UIButton buttonWithType:UIButtonTypeCustom];
    self.previewCancelButton.frame = CGRectMake(Main_Screen_Width-30, SpaceForItems-120, 20, 20);
    [self.previewCancelButton setBackgroundImage:[UIImage imageNamed:@"btn_previewcancel.png"] forState:UIControlStateNormal];
    [self.previewCancelButton setBackgroundImage:[UIImage imageNamed:@"btn_previewcancel.png"] forState:UIControlStateHighlighted];

    [self.previewCancelButton addTarget:self action:@selector(cancelStickerPreviewButtonPressed:) forControlEvents:UIControlEventTouchUpInside];

    [self addSubview: self.previewCancelButton];



/* Cancel sticker preview subview */
- (void)cancelStickerPreviewButtonPressed:(id)sender 

    NSLog(@"cancel sticker preview");
    [self.previewCancelButton removeFromSuperview];
    [stickerPreviewView removeFromSuperview];


现在 previewCancelButton 正确地位于stickerPreviewView 的右上角,但无法接收到它的触摸事件。当我触摸按钮时,它在控制台中显示“111”,当我回溯时,我发现 BaseTemplateVC.m 包含 addDismissKeyboardGesture 方法,所以我相信这可能会导致问题。

任何人都可以指导我找到一些解决方案。那将不胜感激。提前致谢。

进度:我在 ChatroomVC.m 中修改了 gestureRecognizer 方法,所以现在它可以忽略按钮上的点击手势,但问题仍然是按钮的操作没有被触发。

【问题讨论】:

您可以在手势操作功能中检查点击区域,并以编程方式使用.sendAction按下按钮,如果在按钮区域中则立即返回 @Tj3n 我不确定如何检查按钮的点击区域。你能用代码给我看,这样我就能明白你的意思了吗?谢谢。 你能检查一下剪辑是否绑定到是,看看你的按钮是否仍然可见 @MikeAlter 我试过stickerPreviewView.clipsToBounds = YES;self.previewCancelButton.clipsToBounds = YES; 按钮仍然可见。 self.clipsToBounds = YES 看看 【参考方案1】:

试试这个,我想它会工作的。 使用手势的shouldReceiveTouch委托方法,当touch.view为按钮类时返回NO。 所以当它找到按钮时,它会丢弃手势并采取按钮动作。

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

    // Block the recognition of tap gestures in the button.
    if (([touch.view isKindOfClass:[UIButton class]])) 
       return NO;
    

    return YES;

这里是演示实现: 我已经在故事板的视图控制器主视图上按下按钮。

- (void)viewDidLoad 
    [super viewDidLoad];

    UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureClicked:)];
    tapGesture.delegate = self;
    [self.view addGestureRecognizer:tapGesture];

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

    // Disallow recognition of tap gestures in the segmented control.
    if (([touch.view isKindOfClass:[UIButton class]])) 
        return NO;
    
    return YES;

- (IBAction)btnTestClicked:(UIButton *)sender 
    NSLog(@"test button click");


- (void)tapGestureClicked:(UIGestureRecognizer *)recog

    NSLog(@"tap gesture clicked");

希望对您有所帮助。 快乐编码...

【讨论】:

我其实并不想放弃原来的手势,只想在stickerPreviewView子视图中为previewCancelButton添加触摸识别。 它会如你所愿。当您单击按钮时,它将返回 no 到手势,这将导致手势动作不会被触发,因此按钮动作会被触发。当你在手势区域内除了按钮之外,它会调用手势方法。 那么我应该将您的代码放在我现有代码的什么位置?请多多包涵;我非常初学者。谢谢。 检查我已经用演示实现编辑了我的答案。您需要将代理放在哪个视图或 ViewController 中,您将面临手势和按钮动作冲突的问题。 你能显示你的代码吗?顺便问一下,你是否设置了断点并检查光标是否到达 shouldReceiveTouch 方法?【参考方案2】:

我通过在 GestureRecogniser 委托方法中使用以下代码找到了解决方案:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch 
  if ([touch.view isDescendantOfView:IFView.stickerPreviewView]) 
     return NO;
  
     return YES;

它确切地指定了在这种情况下 IFView.stickerPreviewView 将返回 NO 的子视图。同样在 InputFunctionView 中,使用它来添加子视图:

[self.superview addSubview:_stickerPreviewView];

【讨论】:

以上是关于UITapGestureRecognizer 在子视图中阻止 UIButton 的触摸事件的主要内容,如果未能解决你的问题,请参考以下文章

iOS 使用带有 UILabel 的 UITapGestureRecognizer 滑动到下一页

如何为 UIViewController.view 中也具有 UITapGestureRecognizer 的 UIView 挑选和操作 UITapGestureRecognizer?

UITapGestureRecognizer 不适用于 UIView 动画

使用 UITapGestureRecognizer 无法识别的选择器

UIlabel 中的 UITapGestureRecognizer 错误

UITapGestureRecognizer 的问题