UIView的。为什么在其父母的范围之外的子视图没有接触?

时间:2011-04-30 20:14:47

标签: ios uiview hittest

我有一个简单 - 平凡的 - UIView父/子层次结构。一位家长(UIView)。一个孩子(UIButton)。父母边界小于孩子的边界,因此孩子的一部分延伸到其父母的边界框之外。

问题在于:父母的bbox之外的孩子的那些部分接收触摸。只有在父级的bbox内点击才允许子按钮接收触摸。

有人可以建议修复/解决方法吗?

更新

对于那些关注这个问题的人,以下是我实施@Bastians最优秀答案的解决方案:

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

    BOOL isInside = [super pointInside:point withEvent:event];

    // identify the button view subclass
    UIButton *b = (UIButton *)[self viewWithTag:3232];
    CGPoint inButtonSpace = [self convertPoint:point toView:b];

    BOOL isInsideButton = [b pointInside:inButtonSpace withEvent:nil];

    if (isInsideButton) {

        return isInsideButton;

    } // if (YES == isInsideButton)

    return isInside;        
}

5 个答案:

答案 0 :(得分:25)

问题是响应者链。当你触摸显示屏时,它会从父母那里下到孩子身上。

所以......当你触摸屏幕时,父母会看到触摸超出了它自己的范围,所以孩子们甚至都不会问。

执行此操作的功能是hitTest。如果你有自己的UIView类,你可以覆盖它并自己返回按钮。

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

答案 1 :(得分:4)

Per Apple’s own documentation,我发现这样做的最简单,最可靠的方法是覆盖剪切视图的超类中的hitTest:withEvent:,如下所示:

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

    // Convert the point to the target view's coordinate system.
    // The target view isn't necessarily the immediate subview
    CGPoint pointForTargetView = [self.targetView convertPoint:point fromView:self];

    if (CGRectContainsPoint(self.targetView.bounds, pointForTargetView)) {

        // The target view may have its view hierarchy,
        // so call its hitTest method to return the right hit-test view
        return [self.targetView hitTest:pointForTargetView withEvent:event];
    }

    return [super hitTest:point withEvent:event];
}

答案 2 :(得分:2)

前提条件

UIButton(命名为容器)中有一个UIView(名为button1),而button1部分位于容器的边界之外。

<强>问题

button1容器外的部分不会响应点击。

<强>解决方案

从UIView中继承您的容器:

class Container: UIView {
    override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {

        let closeButton = viewWithTag(10086) as! UIButton  //<-- note the tag value
        if closeButton.pointInside(convertPoint(point, toView: closeButton), withEvent: event) {
            return true
        }
        return super.pointInside(point, withEvent: event)
    }
}

不要忘记给你的button1标记10086

答案 3 :(得分:2)

  
      
  • @dugla,谢谢你的提问!
  •   
  • @Bastian和@laoyur,谢谢你的回答!
  •   

Swift 4

override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {

    if yourChildView.point(inside: convert(point, to: yourChildView), with: event) {
        return true
    }

    return super.point(inside: point, with: event)
}

答案 4 :(得分:-1)

我手头有同样的问题。您只需覆盖:

- (BOOL)pointInside:(CGPoint)指向withEvent:(UIEvent *)事件

以下是自定义UIView子类的工作代码,该子类仅为其越界子代创建。

@implementation ARQViewToRightmost

// We should not need to override this one !!!
/*-(UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    if ([self isInside:point])
        return self;
    return nil;
}*/

-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    if ([self isInside:point])
        return YES; // That answer will make hitTest continue recursively probing the view's subviews for hit
    return NO;
}

// Check to see if the point is within the bounds of the view. We've extended the bounds to the max right
// Make sure you do not have any other sibling UIViews to the right of this one as they will never receive events
- (BOOL) isInside:(CGPoint)point
{
    CGFloat maxWidth = CGFLOAT_MAX;
    CGRect rect = CGRectMake(0, 0, maxWidth, self.frame.size.height);
    if (CGRectContainsPoint(rect, point))
        return YES;
    return NO;
}

@end