Subclass UINavigationBar and override - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event so that it returns NO for the rectangle where the view you want to get touches is, and YES otherwise.
For instance:
Subclass of UINavigationBar.h:
@property (nonatomic, strong) NSMutableArray *viewsToIgnoreTouchesFor;
Subclass of UINavigationBar.m:
- (NSMutableArray *)viewsToIgnoreTouchesFor { if (!_viewsToIgnoreTouchesFor) { _viewsToIgnoreTouchesFor = [@[] mutableCopy]; } return _viewsToIgnoreTouchesFor; } - (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event { BOOL pointInSide = [super pointInside:point withEvent:event]; for (UIView *view in self.viewsToIgnoreTouchesFor) { CGPoint convertedPoint = [view convertPoint:point fromView:self]; if ([view pointInside:convertedPoint withEvent:event]) { pointInSide = NO; break; } } return pointInSide; }
In full screen view of the viewDidLoad , where you have a view behind the navigation bar, add these lines to viewDidLoad
UINavigationBarSubclass *navBar = (UINavigationBarSubclass*)self.navigationController.navigationBar; [navBar.viewsToIgnoreTouchesFor addObject:self.buttonBehindBar];
Please note: this will not send touches to the navigation bar, that is, if you add a view that is behind the buttons on the navBar, the buttons on the navBar will not receive strokes.
Swift:
var viewsToIgnore = [UIView]() override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { let ignore = viewsToIgnore.first { let converted = $0.convert(point, from: self) return $0.point(inside: converted, with: event) } return ignore == nil && super.point(inside: point, with: event) }
More on pointInside:withEvent:
see
documentation .
Also, if pointInside:withEvent: does not work as you need, it might be worth trying the code above in hitTest:withEvent: