Question

I have a clear UIView which has gesture recognizers attached to it.

This clear uiview covers the entire super view to allow for the gestures to be invoked from anywhere on it.

Under this clear UIView sit different components such as tables,buttons,collectionview etc.

The clear UIView has no idea what is under it any time.

What I want - if a view which is under the clear uiview can handle a touch event (or any type of gesture) - the clear view should disregard that event - and the event will pass through to the underlying view which could handle it.

I tried

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

but I don't know how to make sure the underlying view can handle it.

Was it helpful?

Solution 4

I used some of these suggestions and used the following solution:

I added the gesture recognizer to the bottom most superview in the heirarchy (and not the top most)

Then in that class over rid

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

    // if v is nil then touch wasn't in this view or its subviews
    if (v == nil)
    {
        return nil;
    }

    // in any case if the topview was hidden than return the default value
    if (self.myTopView.hidden)
    {
        return v;
    }

    // if the view isn't hidden but the touch returned a control - than we can pass the touch to the control
    if ([v isKindOfClass:[UIControl class]])
    {
        return v;
    }

    // decide on what threshold to decide is a touch

    CGFloat threshHold = 40;

    // if the touch wasn't on a control but could initiate a gesture than that view should get the touch
    if (v.gestureRecognizers)
    {
        threshHold = 30;
//        return v;
    }

// check if the threshold should be bigger
    if ([self someCondition])
    {
        threshHold = 100;
    }

// threshold according to its position - this is the dynamic part
    if (point.y > (self.myTopView.frame.origin.y - threshold))
    {
        return self.handleBarView;
    }
    return v;
}

OTHER TIPS

-(id)hitTest:(CGPoint)point withEvent:(UIEvent *)event {
    id hitView = [super hitTest:point withEvent:event];
    if (hitView == self)
    {
            return nil;
    }
    else
    {
        return hitView;
    }
}

Add this to your to clear view.

If the hit on clear view means just return nil.

You can override pointInside: withEvent: method. This method returns a boolean value indicating whether the receiver contains the specified point. So if we return NO then your upper clear view will become transparent for touch events and they will be passed to underlying views.

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event {

// Clear UIView will now respond to touch events if return NO:
 return NO;
}

use below code for your case->

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

    if(hitTestView!=nil){
        //check for gesture
        if([hitTestView.gestureRecognizers count]>0)
            return hitTestView;
        //if it is subclass of UIControl like UIButton etc
        else if([hitTestView isKindOfClass:[UIControl class]])
            return hitTestView;
        //if can handle touches
        else if([hitTestView respondsToSelector:@selector(touchesBegan:withEvent:)])
            return hitTestView;
        else
            return nil;
    }

   else{
       return self;
   }
}

In the above code if the subView which is hitView can anyway handle touch ,we return that object to handle that touch. If there is no such hitTest view, then we return the view itself.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top