防止父视图在子视图作用于它后接收触摸事件

Posted

技术标签:

【中文标题】防止父视图在子视图作用于它后接收触摸事件【英文标题】:Prevent parent view from receiving touch event after child view acts on it 【发布时间】:2012-10-09 06:27:29 【问题描述】:

我在 ios 应用上的事件响应者链遇到问题。

问题如下,我在一个更大的视图(正方形)上有一组子视图(气泡),如果我点击按钮,我希望能够显示某个视图,但是如果我点击其他任何地方我想要隐藏相同的视图。

问题是当我点击气泡时,两个视图(子视图和父视图)都在触发,我该如何防止这种情况发生?

如果孩子已经对触摸事件采取了行动,那不应该是它的结束吗?

我的 Bubbles 使用 UITapGestureRecognizer 识别 Tap 手势,而父视图(正方形)使用 touchesBegan: 方法

这张图用多个气泡解释了我当前的设置:

代码:

@implementation Bubble
...
-(id) initWithFrame: (CGRect) frame 
    UITapGestureRecognizer *singleFingerDTap = [[UITapGestureRecognizer alloc]
                                                initWithTarget:self action:@selector(handleSingleTap:)];
    singleFingerDTap.numberOfTapsRequired = 1;
    [self addGestureRecognizer:singleFingerDTap];



-(void) handleSingleTap 
NSLog(@"Bubble tapped, show the view");

对于方形

@implementation Square
...
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event 
NSLog(@"square touched, lets hide the view");

点击后,我在控制台上看到了两个 NSLog

【问题讨论】:

@LithuT.V 包含代码示例 【参考方案1】:

嗯,这就是问题所在。 touchesBegan 将获得所有的触摸,包括手势识别器的触摸。您也可以尝试设置gestureRecognizer.cancelsTouchesInView = TRUE 或使用 touchesBegan 作为您的气泡。

既然你好像在这里做游戏,你是在用cocos2D这样的引擎吗? 如果是这种情况,有更简单的方法可以实现您想要的。

希望这会有所帮助。

干杯!

编辑:

如果您只使用手势识别器,触摸将不会发送到层次结构中的下一个视图。我想这就是你想要的。如果你决定开始接触,我认为你应该这样做:

//在气泡视图类中

- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent *)event 

    if(theTouchLocation is inside your bubble)
    
        do something with the touch
    
    else
    
        //send the touch to the next view in the hierarchy ( your large view )
       [super touchesBegan:touches withEvent:event];
       [[self nextResponder] touchesBegan:touches withEvent:event];
    

【讨论】:

很好的答案!我想我也可以更改 Square 以使用手势识别器点击,但是有没有办法阻止事件从气泡传递到 nextResponder??【参考方案2】:

我找到了问题所在。 UIView 继承自 UIResponder,基本的触摸事件由触发触摸开始事件的视图检测。您在主视图中添加的子视图也响应 touches started 方法。这是非常基本的。您还添加了一个带有点击手势识别器的选择器方法。因此,对气泡的任何触摸都会触发这两种方法,从而触发两个日志。尝试使用另一个选择器将另一个手势识别器添加到视图中,例如

UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tappedOnBubble)];
    [self.bubbleView addGestureRecognizer:tap];

UITapGestureRecognizer *tap2 = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tappedOnMainView)];
   [self.view addGestureRecognizer:tap2];


-(void)tappedOnMainView

    NSLog(@"touched on main View");
    [self.vwToShow setHidden:NO];

-(void)tappedOnView

    NSLog(@"tapped on bubbleview");
    [self.vwToShow setHidden:YES];

【讨论】:

【参考方案3】:

这样做:

@implementation Square

 ...
 -(id) initWithFrame: (CGRect) frame 
    UITapGestureRecognizer *singleFingerDTap = [[UITapGestureRecognizer alloc]
                                                initWithTarget:self action:@selector(handleSingleTap:)];
    singleFingerDTap.numberOfTapsRequired = 1;
    [self addGestureRecognizer:singleFingerDTap];

 

 -(void) handleSingleTap 
   NSLog(@"Sqaure tapped, hide the view");
 


【讨论】:

它们不是按钮 :) 它们是自定义 UIView 的【参考方案4】:

为什么不在主视图上也使用点击手势识别器呢?触摸开始就像编写自己的手势识别器,但要困难得多。使用多个水龙头识别器时,只有一个会触发。

【讨论】:

我需要要求 Square 识别器从气泡中失败还是向后失败? @PERR0_HUNTER 有时自己尝试比等别人告诉你更快。

以上是关于防止父视图在子视图作用于它后接收触摸事件的主要内容,如果未能解决你的问题,请参考以下文章

子 UIViewController 视图阻止容器 UIViewController 视图接收触摸事件

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

在 Android 中的多个视图上同时处理触摸事件

UIView clipToBounds 没有停止子视图接收父视图之外的触摸

将触摸事件传递给父视图

响应者链