37

我有一个简单的 - 微不足道的 - UIView 父/子层次结构。一位家长(UIView)。一个孩子(UIButton)。父母的界限比它的孩子的界限更小,因此孩子的一部分延伸到其父母的边界框之外。

这就是问题所在:在父母的 bbox 之外的孩子的那些部分没有收到触摸。只有在父的 bbox 内点击才允许子按钮接收触摸。

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

更新

对于那些关注这个问题的人,这是我根据@Bastian 最出色的答案实施的解决方案:

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

5 回答 5

26

问题是响应者链。当您触摸显示屏时,它会从父母传给孩子。

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

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

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
于 2011-04-30T20:22:42.253 回答
4

根据Apple 自己的文档,我发现的最简单和最可靠的方法是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];
}
于 2014-08-30T18:37:29.667 回答
2

前提条件

您在(命名为容器)中有一个UIButton(命名为 button1)UIView,并且 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

于 2016-12-21T06:23:39.450 回答
2
  • @dugla,谢谢你的提问!
  • @Bastian 和 @laoyur,感谢您的回答!

斯威夫特 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)
}
于 2018-02-14T22:05:47.693 回答
-1

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

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

这是一个自定义 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
于 2013-06-04T10:51:00.167 回答