Allow UIScrollView and its subviews to both respond to a touch

前端 未结 5 572
轮回少年
轮回少年 2020-12-04 16:11

I want both my UIScrollView and its subviews to receive all touch events inside the subview. Each can respond in its own way.

Alternatively, if tap gestures were fo

5条回答
  •  天命终不由人
    2020-12-04 16:33

    A hackish way to achieve your objective - not 100% exact - is to subclass the UIWindow and override the - (void)sendEvent:(UIEvent *)event;

    A quick example:

    in SecondResponderWindow.h header

    //SecondResponderWindow.h
    
    @protocol SecondResponderWindowDelegate
    - (void)userTouchBegan:(id)tapPoint onView:(UIView*)aView;
    - (void)userTouchMoved:(id)tapPoint onView:(UIView*)aView;
    - (void)userTouchEnded:(id)tapPoint onView:(UIView*)aView;
    @end
    
    @interface SecondResponderWindow : UIWindow
    @property (nonatomic, retain) UIView *viewToObserve;
    @property (nonatomic, assign) id  controllerThatObserves;
    @end
    

    in SecondResponderWindow.m

    //SecondResponderWindow.m
    
    - (void)forwardTouchBegan:(id)touch onView:(UIView*)aView {
        [controllerThatObserves userTouchBegan:touch onView:aView];
    }
    - (void)forwardTouchMoved:(id)touch onView:(UIView*)aView {
        [controllerThatObserves userTouchMoved:touch onView:aView];
    }
    - (void)forwardTouchEnded:(id)touch onView:(UIView*)aView {
        [controllerThatObserves userTouchEnded:touch onView:aView];
    }
    
    - (void)sendEvent:(UIEvent *)event {
        [super sendEvent:event];
    
        if (viewToObserve == nil || controllerThatObserves == nil) return;
    
        NSSet *touches = [event allTouches];
        UITouch *touch = [touches anyObject];
        if ([touch.view isDescendantOfView:viewToObserve] == NO) return;
    
        CGPoint tapPoint = [touch locationInView:viewToObserve];
        NSValue *pointValue = [NSValue valueWithCGPoint:tapPoint];
    
        if (touch.phase == UITouchPhaseBegan)
            [self forwardTouchBegan:pointValue onView:touch.view];
        else if (touch.phase == UITouchPhaseMoved)
            [self forwardTouchMoved:pointValue onView:touch.view];
        else if (touch.phase == UITouchPhaseEnded)
            [self forwardTouchEnded:pointValue onView:touch.view];
        else if (touch.phase == UITouchPhaseCancelled)
            [self forwardTouchEnded:pointValue onView:touch.view];
    }
    

    It's not 100% conforms to what your were expecting - because your second responder view does not handle the touch event natively via -touchDidBegin: or so, and has to implement the SecondResponderWindowDelegate. However this hack does allow you to handle touch events on additional responders.

    This method is inspired by and extended from MITHIN KUMAR's TapDetectingWindow

提交回复
热议问题