Touch events within ~8 pixels of nav bar not calle

2019-03-15 17:26发布

问题:

I have an application with three buttons (actually UIView's) laid out horizontally underneath the navigation bar.

The three buttons are of substantial enough size (larger than the back button, for example), however they won't respond to touches when the hit is in the top third part, roughly.

I'm aware that this area directly underneath the nav bar is sort of 'reserved' for the back button and other UINavigation items having a touch area that expands beyond the navigation bar (by quite a significant margin), however in some instance there isn't even a navigation item nearby to steal the event, and my views still don't respond.

The weird thing is that I am getting a call to the hitTest method in my UIView, just never a touchesBegan/Ended/etc.

The result is that it is very difficult to press the buttons and if one is anywhere near a UINavigationItem, the item will steal the event, even though in hitTest I am returning the correct UIView to the system.

Unfortunately I am the implementer and not the designer so a design change is a last resort.

Any ideas? Thanks!

回答1:

You have to subclass your UINavigationBar and in your CustomNavigationBar do this:

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

    if ([self pointInside:point withEvent:event]) {
        self.userInteractionEnabled = YES;
    } else {
        self.userInteractionEnabled = NO;
    }

    return [super hitTest:point withEvent:event];
}

Info about how to subclass UINavigationBar you can find here.



回答2:

The code provided by @Andrei will cause controller stack inconsistency on iOS 7 when quickly push and pop controllers. The system itself will change the userInteractionEnabled property before and after push/pop animations. Here is how I fixed this issue.

@interface DMNavigationBar ()

@property (nonatomic, assign) BOOL changingUserInteraction;
@property (nonatomic, assign) BOOL userInteractionChangedBySystem;

@end

@implementation DMNavigationBar

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    if (self.userInteractionChangedBySystem && self.userInteractionEnabled == NO)
    {
        return [super hitTest:point withEvent:event];
    }

    if ([self pointInside:point withEvent:event])
    {
        self.changingUserInteraction = YES;
        self.userInteractionEnabled = YES;
        self.changingUserInteraction = NO;
    }
    else
    {
        self.changingUserInteraction = YES;
        self.userInteractionEnabled = NO;
        self.changingUserInteraction = NO;
    }

    return [super hitTest:point withEvent:event];
}

- (void)setUserInteractionEnabled:(BOOL)userInteractionEnabled
{
    if (!self.changingUserInteraction)
    {
        self.userInteractionChangedBySystem = YES;
    }
    else
    {
        self.userInteractionChangedBySystem = NO;
    }

    [super setUserInteractionEnabled:userInteractionEnabled];
}

@end


回答3:

Had the same problem and the above answers are good and they point to a concise solution.

The same answer for the swift version:

  class APLVNavigationBar: UINavigationBar {
override func hitTest(point: CGPoint, withEvent event: UIEvent?) -> UIView? {
    if pointInside(point, withEvent: event){
        userInteractionEnabled = true
    }else{
        userInteractionEnabled = false
    }
    return super.hitTest(point, withEvent: event)
  }
}


回答4:

I dont think that it is the problem, but did you bring the button subviews to the front?

[self.view bringSubviewToFront:buttonView]