当很清楚并且不同的uiview可以处理它们时,如何忽略最上面的uiview中的触摸事件

Posted

技术标签:

【中文标题】当很清楚并且不同的uiview可以处理它们时,如何忽略最上面的uiview中的触摸事件【英文标题】:how to disregard touch events in topmost uiview when it is clear and a different uiview can handle them 【发布时间】:2014-02-20 13:11:57 【问题描述】:

我有一个清晰的 UIView,上面附有手势识别器。

这个清晰的 uiview 覆盖了整个超级视图,以允许从其上的任何位置调用手势。

在这个清晰的 UIView 下有不同的组件,例如表格、按钮、集合视图等。

清晰的 UIView 随时都不知道下面是什么。

我想要什么 - 如果清晰 uiview 下的视图可以处理触摸事件(或任何类型的手势) - 清晰视图应该忽略该事件 - 并且事件将传递到可以处理的底层视图它。

我试过了

-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

但我不知道如何确保底层视图可以处理它。

【问题讨论】:

这个清晰视图的目的是什么? 我认为你可以使用手势识别器委托方法gestureRecognizer:shouldReceiveTouch:来做到这一点。设置一个条件,如果触摸在您想要接收的控件的矩形内,则手势将被忽略,按钮将接收触摸。 这个问题你解决了吗? 【参考方案1】:
-(id)hitTest:(CGPoint)point withEvent:(UIEvent *)event 
    id hitView = [super hitTest:point withEvent:event];
    if (hitView == self)
    
            return nil;
    
    else
    
        return hitView;
    

将此添加到您的清晰视图中。

如果点击清晰视图意味着返回 nil。

【讨论】:

超级视图如何将事件传递给相关视图 命中测试不同于superview子视图的概念。 touch 总是从应用程序窗口开始并沿着应用程序中的所有视图移动。您的应用程序中的每个视图都将收到 hitevent 如果return nil的意思,说明这个view不需要触摸事件【参考方案2】:

您可以覆盖pointInside: withEvent: 方法。该方法返回一个布尔值,指示接收器是否包含指定的点。因此,如果我们返回NO,那么您的上层清晰视图将对触摸事件变得透明,并且它们将被传递给底层视图。

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event 

// Clear UIView will now respond to touch events if return NO:
 return NO;

【讨论】:

【参考方案3】:

为您的案例使用以下代码->

-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
    UIView *hitTestView = [super hitTest:point withEvent:event];

    if(hitTestView!=nil)
        //check for gesture
        if([hitTestView.gestureRecognizers count]>0)
            return hitTestView;
        //if it is subclass of UIControl like UIButton etc
        else if([hitTestView isKindOfClass:[UIControl class]])
            return hitTestView;
        //if can handle touches
        else if([hitTestView respondsToSelector:@selector(touchesBegan:withEvent:)])
            return hitTestView;
        else
            return nil;
    

   else
       return self;
   

在上面的代码中,如果作为 hitView 的 subView 无论如何都可以处理触摸,我们返回那个对象来处理那个触摸。如果没有这样的 hitTest 视图,那么我们返回视图本身。

【讨论】:

【参考方案4】:

我使用了其中的一些建议并使用了以下解决方案:

我将手势识别器添加到层次结构中最底部的超级视图(而不是最顶部)

然后在那个班级里摆脱

-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event

    UIView *v = [super hitTest:point withEvent:event];

    // if v is nil then touch wasn't in this view or its subviews
    if (v == nil)
    
        return nil;
    

    // in any case if the topview was hidden than return the default value
    if (self.myTopView.hidden)
    
        return v;
    

    // if the view isn't hidden but the touch returned a control - than we can pass the touch to the control
    if ([v isKindOfClass:[UIControl class]])
    
        return v;
    

    // decide on what threshold to decide is a touch

    CGFloat threshHold = 40;

    // if the touch wasn't on a control but could initiate a gesture than that view should get the touch
    if (v.gestureRecognizers)
    
        threshHold = 30;
//        return v;
    

// check if the threshold should be bigger
    if ([self someCondition])
    
        threshHold = 100;
    

// threshold according to its position - this is the dynamic part
    if (point.y > (self.myTopView.frame.origin.y - threshold))
    
        return self.handleBarView;
    
    return v;

【讨论】:

以上是关于当很清楚并且不同的uiview可以处理它们时,如何忽略最上面的uiview中的触摸事件的主要内容,如果未能解决你的问题,请参考以下文章

CALayer 详解

SQLAlchemy:如何在删除时禁用 ORM 级外键处理?

通过在它们上方移动另一个 UIView 来获取所有 UIViews

如何创建自定义 UIView?

如何在 Interface Builder 中存储键/值并在运行时访问它们?

如何打乱一组 UIViews