1

I'm trying to create an overlay view that monitors for touches and then disappears, but also forwards touch events to whatever is underneath the view.

My test app has a view with a button inside. I add the overlay view as another subview (sibling to the button, essentially), which takes up the entire screen.

For both solutions I tried, the overlay keeps state to determine how it responds to a touch. When a touchesBegan event is received, the overlay will stop responding to hitTest or pointInside until it receives a touchesCancelled or touchesEnded.

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    if(_respondToTouch)
    {
        NSLog(@"Responding to hit test");
        return [super hitTest:point withEvent:event];
    }
    NSLog(@"Ignoring hit test");
    return nil;
}

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event
{
    if(_respondToTouch)
    {
        NSLog(@"Responding to point inside");
        return [super pointInside:point withEvent:event];
    }
    NSLog(@"Ignoring point inside");
    return NO;
}

For my first approach, I tried re-issuing the event:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    if(!_respondToTouch)
    {
        NSLog(@"Ignoring touches began");
        return;
    }
    NSLog(@"Responding to touches began");
    _respondToTouch = NO;

    [[UIApplication sharedApplication] sendEvent:event];
}

- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"Touches cancelled");
    _respondToTouch = YES;
}

- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"Touches ended");
    _respondToTouch = YES;
}

However, the button didn't respond to the re-issued event.

My second approach was to use hitTest to discover the view (my button) underneath the overlay, and then send a touchesXXX message directly to it:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"Touches began");
    _respondToTouch = NO;
    UITouch* touch = [touches anyObject];
    _touchDelegate = [[UIApplication sharedApplication].keyWindow hitTest:[touch locationInView:self.superview] withEvent:event];
    CGPoint locationInView = [touch locationInView:_touchDelegate];
    NSLog(@"Sending touch %@ to view %@. location in view = %f, %f", touch, _touchDelegate, locationInView.x, locationInView.y);
    [_touchDelegate touchesBegan:touches withEvent:event];
}

- (void) touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"Touches cancelled");
    [_touchDelegate touchesCancelled:touches withEvent:event];
    _respondToTouch = YES;
}

- (void) touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"Touches ended");
    [_touchDelegate touchesEnded:touches withEvent:event];
    _respondToTouch = YES;
}

- (void) touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    NSLog(@"Touches moved");
    [_touchDelegate touchesMoved:touches withEvent:event];
}

It finds the button (according to the logs), but the button doesn't react at all when I invoke touchesXXX on it.

I'm not sure what else to try since the button won't respond to a direct invocation of touchesBegan =/

Karl
  • 14,434
  • 9
  • 44
  • 61
  • [This article](http://cocoawithlove.com/2008/10/synthesizing-touch-event-on-iphone.html) might be helpful for you. You might want to synthesize an identical touch event with a timer maybe 10 milliseconds or so after your overlay view intercepts the original touch event. – Alex Nichol Jul 23 '11 at 02:27
  • Unfortunately, that solution makes use of private API calls, so I can't use it. – Karl Jul 24 '11 at 21:49

0 Answers0