Why does UINavigationBar steal touch events?

后端 未结 12 2603
耶瑟儿~
耶瑟儿~ 2020-11-27 18:48

I have a custom UIButton with UILabel added as subview. Button perform given selector only when I touch it about 15points lower of top bound. And when I tap above that area

12条回答
  •  鱼传尺愫
    2020-11-27 19:24

    Extending Alexander's solution:

    Step 1. Subclass UIWindow

    @interface ChunyuWindow : UIWindow {
        NSMutableArray * _views;
    
    @private
        UIView *_touchView;
    }
    
    - (void)addViewForTouchPriority:(UIView*)view;
    - (void)removeViewForTouchPriority:(UIView*)view;
    
    @end
    // .m File
    // #import "ChunyuWindow.h"
    
    @implementation ChunyuWindow
    - (void) dealloc {
        TT_RELEASE_SAFELY(_views);
        [super dealloc];
    }
    
    
    - (void)motionBegan:(UIEventSubtype)motion withEvent:(UIEvent *)event {
        if (UIEventSubtypeMotionShake == motion
            && [TTNavigator navigator].supportsShakeToReload) {
            // If you're going to use a custom navigator implementation, you need to ensure that you
            // implement the reload method. If you're inheriting from TTNavigator, then you're fine.
            TTDASSERT([[TTNavigator navigator] respondsToSelector:@selector(reload)]);
            [(TTNavigator*)[TTNavigator navigator] reload];
        }
    }
    
    - (void)addViewForTouchPriority:(UIView*)view {
        if ( !_views ) {
            _views = [[NSMutableArray alloc] init];
        }
        if (![_views containsObject: view]) {
            [_views addObject:view];
        }
    }
    
    - (void)removeViewForTouchPriority:(UIView*)view {
        if ( !_views ) {
            return;
        }
    
        if ([_views containsObject: view]) {
            [_views removeObject:view];
        }
    }
    
    - (void)sendEvent:(UIEvent *)event {
        if ( !_views || _views.count == 0 ) {
            [super sendEvent:event];
            return;
        }
    
        UITouch *touch = [[event allTouches] anyObject];
        switch (touch.phase) {
            case UITouchPhaseBegan: {
                for ( UIView *view in _views ) {
                    if ( CGRectContainsPoint(view.frame, [touch locationInView:[view superview]]) ) {
                        _touchView = view;
                        [_touchView touchesBegan:[event allTouches] withEvent:event];
                        return;
                    }
                }
                break;
            }
            case UITouchPhaseMoved: {
                if ( _touchView ) {
                    [_touchView touchesMoved:[event allTouches] withEvent:event];
                    return;
                }
                break;
            }
            case UITouchPhaseCancelled: {
                if ( _touchView ) {
                    [_touchView touchesCancelled:[event allTouches] withEvent:event];
                    _touchView = nil;
                    return;
                }
                break;
            }
            case UITouchPhaseEnded: {
                if ( _touchView ) {
                    [_touchView touchesEnded:[event allTouches] withEvent:event];
                    _touchView = nil;
                    return;
                }
                break;
            }
    
            default: {
                break;
            }
        }
    
        [super sendEvent:event];
    }
    
    @end
    

    Step 2: Assign ChunyuWindow instance to AppDelegate Instance

    Step 3: Implement touchesEnded:widthEvent: for view with buttons, for example:

    - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
        [super touchesEnded: touches withEvent: event];
    
        UITouch *touch = [touches anyObject];
        CGPoint point = [touch locationInView: _buttonsView]; // a subview contains buttons
        for (UIButton* button in _buttons) {
            if (CGRectContainsPoint(button.frame, point)) {
                [self onTabButtonClicked: button];
                break;
            }
        }    
    }
    

    Step 4: call ChunyuWindow's addViewForTouchPriority when the view we care about appears, and call removeViewForTouchPriority when the view disappears or dealloc, in viewDidAppear/viewDidDisappear/dealloc of ViewControllers, so _touchView in ChunyuWindow is NULL, and it is the same as UIWindow, having no side effects.

提交回复
热议问题