Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to prevent UINavigationBar from blocking touches on view

I have a UIView that is partially stuck underneath a UINavigationBar on a UIViewController that's in full screen mode. The UINavigationBar blocks the touches of this view for the portion that it's covering it. I'd like to be able to unblock these touches for said view and have them go through. I've subclassed UINavigationBar with the following:

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    UIView *view = [super hitTest:point withEvent:event];

    if (view.tag == 399)
    {
        return view;
    }
    else
    {
        return nil;
    }
}

...where I've tagged the view in question with the number 399. Is it possible to pass through the touches for this view without having a pointer to it (i.e. like how I've tagged it above)? Am a bit confused on how to make this work with the hittest method (or if it's even possible).

like image 266
Ser Pounce Avatar asked Feb 17 '14 08:02

Ser Pounce


1 Answers

I modified Tricky's solution to work with SwiftUI as an Extension. Works great to solve this problem. Once you add this code to your codebase all views will be able to capture clicks at the top of the screen.

Also posted this alteration to my blog.

import UIKit

/// Passes through all touch events to views behind it, except when the
/// touch occurs in a contained UIControl or view with a gesture
/// recognizer attached
extension UINavigationBar {
    open override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
        guard nestedInteractiveViews(in: self, contain: point) else { return false }
        return super.point(inside: point, with: event)
    }

    private func nestedInteractiveViews(in view: UIView, contain point: CGPoint) -> Bool {
        if view.isPotentiallyInteractive, view.bounds.contains(convert(point, to: view)) {
            return true
        }

        for subview in view.subviews {
            if nestedInteractiveViews(in: subview, contain: point) {
                return true
            }
        }

        return false
    }
}

private extension UIView {
    var isPotentiallyInteractive: Bool {
        guard isUserInteractionEnabled else { return false }
        return (isControl || doesContainGestureRecognizer)
    }

    var isControl: Bool {
        return self is UIControl
    }

    var doesContainGestureRecognizer: Bool {
        return !(gestureRecognizers?.isEmpty ?? true)
    }
}
like image 65
dragonfire Avatar answered Sep 21 '22 15:09

dragonfire