4

I have TransparentUIView on top of RedOrGreenUIView. TransparentUIView has a UILongPressGestureRecognizer attached to it. Once user begins a long touch on it, I check for .Changed status of this LongPressGesture, and execute below hitTest:

var p:CGPoint = rec.locationInView(self.view)
var selectedView = view.hitTest(p, withEvent: nil)
if selectedView != nil {
   if selectedView == TransparentUIView {
       println("TransparentUIView is being touched")
   }
}

I get TransparentView as selectedView fine. However I need to be able to conduct a hitTest on RedOrGreenUIView at the same time, which is underneath TransparentUIView. I cant get my head around to accomplishing this. Please help.

Kashif
  • 4,642
  • 7
  • 44
  • 97

4 Answers4

13

Create a custom view for your container and override the pointInside: message to return NO when the point isn't within an eligible child view, like this:

@interface PassthroughView : UIView
@end

@implementation PassthroughView
-(BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {
    for (UIView *view in self.subviews) {
        if (!view.hidden && view.alpha > 0 && view.userInteractionEnabled && [view pointInside:[self convertPoint:point toView:view] withEvent:event])
            return YES;
    }
    return NO;
}
@end

swift version

class PassThroughView: UIView {

     override func pointInside(point: CGPoint, withEvent event: UIEvent?) -> Bool {
            for subview in subviews as [UIView] {
                if !subview.hidden && subview.alpha > 0 && subview.userInteractionEnabled && subview.pointInside(convertPoint(point, toView: subview), withEvent: event) {
                    return true
                }
            }
            return false
        }
    }
LC 웃
  • 18,888
  • 9
  • 57
  • 72
Suraj K Thomas
  • 5,773
  • 4
  • 52
  • 64
  • 1
    In the pass though UIView, there is a stackView with buttons in a grid, the gaps between the buttons are stackView spacing. The stackView spacing does not pass touch to the view below. How can I pass touches through the stackView spacing please? – theMouse Aug 13 '16 at 20:02
3

Swift 4 version :

 override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        for subview in YourView.subviews as [UIView] {

            if !subview.isHidden && subview.alpha > 0 && subview.isUserInteractionEnabled && subview.point(inside:point, with: event) {
                return true
            }
        }

    return false
 }
Community
  • 1
  • 1
byJeevan
  • 3,728
  • 3
  • 37
  • 60
1

If one UIView gets touches, others underneath don't get any.

So either you can have a central class that passes touches to both your UIView objects, or the first UIView, the one that is on top, passes its UITouch object to the UIView underneath and conducts the hitTest.

Shamas S
  • 7,507
  • 10
  • 46
  • 58
  • 1
    Alternatively, I could suggest using method swizzling to get touches and posting them everywhere, but let's walk before we run, shall we? :) – Shamas S Mar 17 '15 at 19:32
  • I like the second option. Would you be kind enough to tell me how to pass UITouch object to another view. All the help I googled is in ObjC which I don't understand. – Kashif Mar 17 '15 at 19:32
  • 1
    @TPos In your UIView implement methods touchesBegan, touchesMoved and touchesEnded. This would give you UITouch object in this view. Once you get them, you can use them for your hitTest or send those objects to the views underneath. For that you write a function in the view underneath and pass UITouch object as a parameter. – Shamas S Mar 17 '15 at 19:38
1

I am currently working on a transparent Help Overlay for iOS apps and was looking for a good answer on this myself.

I couldn't really find anything, so decided to look a bit further. The apple documentation on hitTest says it doesn't include views that have a transparency of < 0.1, are hidden or have userInteractionEnabled to false.

That last one gave me an idea and it's something that seems to work pretty good.

Try the following (I still need to test it further, but it seems to be allright):

var p:CGPoint = rec.locationInView(self.view)

TransparentUIView.isUserInteractionEnabled = false

var selectedView = view.hitTest(p, withEvent: nil)

TransparentUIView.isUserInteractionEnabled = true

if selectedView != nil {
    if selectedView == TransparentUIView {
        println("TransparentUIView is being touched")
    }
}