Interaction beyond bounds of UIView

2019-01-04 17:35发布

Is it possible for a UIButton (or any other control for that matter) to receive touch events when the UIButton's frame lies outside of it's parent's frame? Cause when I try this, my UIButton doesn't seem to be able to receive any events. How do I work around this?

8条回答
Melony?
2楼-- · 2019-01-04 17:50

In my case, I had a UICollectionViewCell subclass that contained a UIButton. I disabled clipsToBounds on the cell and the button was visible outside of the cell's bounds. However, the button was not receiving touch events. I was able to detect the touch events on the button by using Jack's answer: https://stackoverflow.com/a/30431157/3344977

Here's a Swift version:

override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {

    let translatedPoint = button.convertPoint(point, fromView: self)

    if (CGRectContainsPoint(button.bounds, translatedPoint)) {
        print("Your button was pressed")
        return button.hitTest(translatedPoint, withEvent: event)
    }
    return super.hitTest(point, withEvent: event)
}
查看更多
冷血范
3楼-- · 2019-01-04 17:54

swift 4.1 updated

To get touch events in same UIView you just need to add following override method, it will identify specific view tapped in UIView which is placed out of bound

override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
    let pointforTargetview:CGPoint = self.convert(point, to: btnAngle)
    if  btnAngle.bounds.contains(pointforTargetview) {
        return  self
    }
    return super.hitTest(point, with: event)
}
查看更多
做个烂人
4楼-- · 2019-01-04 18:02

Swift:

Where targetView is the view you wish to receive the event (which may be entirely or partially located outside of the frame of its parent view).

override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
        let pointForTargetView: CGPoint = targetView.convertPoint(point, fromView: self)
        if CGRectContainsPoint(targetView.bounds, pointForTargetView) {
            return closeButton
        }
        return super.hitTest(point, withEvent: event)
}
查看更多
贼婆χ
5楼-- · 2019-01-04 18:04

For me (as for others), the answer was not to override the hitTest method, but rather the pointInside method. I had to do this in only two places.

The Superview This is the view that if it had clipsToBounds set to true, it would make this whole problem disappear. So here's my simple UIView in Swift 3:

class PromiscuousView : UIView {
    override func point(inside point: CGPoint,
               with event: UIEvent?) -> Bool {
        return true
    }
} 

The Subview Your mileage may vary, but in my case I also had to overwrite the pointInside method for the subview that was had decided the touch was out of bounds. Mine is in Objective-C, so:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    WEPopoverController *controller = (id) self.delegate;
    if (self.takeHitsOutside) {
        return YES;
    } else {
        return [super pointInside:point withEvent:event];
    }
}

This answer (and a few others on the same question) can help clear up your understanding.

查看更多
太酷不给撩
6楼-- · 2019-01-04 18:08

@jnic, I am working on iOS SDK 5.0 and in order to get your code working right I had to do this:

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
if (CGRectContainsPoint(button.frame, point)) {
    return YES;
}
return [super pointInside:point withEvent:event]; }

The container view in my case is a UIButton and all the child elements are also UIButtons that can move outside the bounds of the parent UIButton.

Best

查看更多
老娘就宠你
7楼-- · 2019-01-04 18:13

In the parent view you can override the hit test method:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    CGPoint translatedPoint = [_myButton convertPoint:point fromView:self];

    if (CGRectContainsPoint(_myButton.bounds, translatedPoint)) {
        return [_myButton hitTest:translatedPoint withEvent:event];
    }
    return [super hitTest:point withEvent:event];

}

In this case, if the point falls within the bounds of your button, you forward the call there; if not, revert to the original implementation.

查看更多
登录 后发表回答