Passing touches between stacked UIWindows?

Ok, here's what I did: I created two views in the front window. The first view covered the area where I wanted to catch the touches; the second, where I wanted the touches to pass through. I sub-classed UIWindow and overrode the hitTest:withEvent method like so:

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

  // See if the hit is anywhere in our view hierarchy
  UIView *hitTestResult = [super hitTest:point withEvent:event];

  // ABKSlideupHostOverlay view covers the pass-through touch area.  It's recognized
  // by class, here, because the window doesn't have a pointer to the actual view object.
  if ([hitTestResult isKindOfClass:[ABKSlideupHostOverlayView class]]) {

    // Returning nil means this window's hierachy doesn't handle this event. Consequently,
    // the event will be passed to the host window.
    return nil;
  }

  return hitTestResult;
}

And in the class which creates the front window, I used a gesture recognizer to catch touches on the first view.


Same in 2017 code:

class PassView: UIView {}

class UIHigherWindow: UIWindow {

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

        let hitView = super.hitTest(point, with: event)

        if hitView!.isKind(of: PassView.self) {

            return nil
        }

        return hitView
    }
}

Your "uber" window will be some view controller, UberVc.

Just make the main view (that is to say, simply the background .view) of UberVc be a PassView.

Then add say buttons etc. on the UberVc.

The above code results in any clicks on the buttons going to UberVc, and any clicks not on the buttons (ie, on the "background") going through to your regular window/VCs.


I had a similar issue: the additional UIWindow should have a transparent view on it with some intractable subviews. All touches outside of those intractable views must be passed through.

I ended up using modified version of Anna's code that uses view's tag instead of type checking. This way view subclass creation is not required:

class PassTroughWindow: UIWindow {
    var passTroughTag: Int?

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

        let hitView = super.hitTest(point, with: event)

        if let passTroughTag = passTroughTag {
            if passTroughTag == hitView?.tag {
                return nil
            }
        }
        return hitView
    }
}

Assuming you have a window and root view controller created you you could use it like this:

let window: PassTroughWindow 
//Create or obtain window

let passTroughTag = 42

window.rootViewController.view.tag = passTroughTag
window.passTroughTag = passTroughTag

//Or with a view:
let untouchableView: UIView // Create it
untouchableView.tag = passTroughTag
window.addSubview(untouchableView)