Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UIView's -hitTest:withEvent: called three times?

I am trying to intercept any activity (i.e. touches) that happens inside my whole application.

In other words, I am trying to be notified of any touch event that happens within my main UIView, containing the rest of my controls. To do so, I thought the UIView's method -hitTest:withEvent: was a good solution.

However, when I NSLog into this overriden method before calling [super hitTest:... withEvent:...], I see that it is called 3 times for any touch I make, and I cannot see any difference in the event I receive each time it is called.

Here is how is implemented the method in the main view of my application :

- (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event
{
    NSLog(@"hitTest:withEvent called :");
    NSLog(@"Event: %@", event);
    NSLog(@"Point: %@", NSStringFromCGPoint(point));
    NSLog(@"Event Type: %d", event.type);
    NSLog(@"Event SubType: %d", event.subtype);
    NSLog(@"---");

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

And here is what I NSLog for a single touch in this view :

2010-11-29 14:09:26.892 Application[68818:207] hitTest:withEvent called :
2010-11-29 14:09:26.892 Application[68818:207] Event: <UITouchesEvent: 0x5716d60> timestamp: 37935.2 touches: {(
)}
2010-11-29 14:09:26.892 Application[68818:207] Point: {173, 498}
2010-11-29 14:09:26.892 Application[68818:207] Event Type: 0
2010-11-29 14:09:26.892 Application[68818:207] Event SubType: 0
2010-11-29 14:09:26.893 Application[68818:207] ---
2010-11-29 14:09:26.893 Application[68818:207] hitTest:withEvent called :
2010-11-29 14:09:26.893 Application[68818:207] Event: <UITouchesEvent: 0x5716d60> timestamp: 37935.2 touches: {(
)}
2010-11-29 14:09:26.893 Application[68818:207] Point: {173, 498}
2010-11-29 14:09:26.893 Application[68818:207] Event Type: 0
2010-11-29 14:09:26.893 Application[68818:207] Event SubType: 0
2010-11-29 14:09:26.893 Application[68818:207] ---
2010-11-29 14:09:26.893 Application[68818:207] hitTest:withEvent called :
2010-11-29 14:09:26.894 Application[68818:207] Event: <UITouchesEvent: 0x5716d60> timestamp: 37944.9 touches: {(
)}
2010-11-29 14:09:26.894 Application[68818:207] Point: {173, 498}
2010-11-29 14:09:26.894 Application[68818:207] Event Type: 0
2010-11-29 14:09:26.894 Application[68818:207] Event SubType: 0
2010-11-29 14:09:26.894 Application[68818:207] ---

How could I make any difference between those three notifications in order to trigger the action I want to make only one time for a single touch ?

Thanks in advance !

like image 587
Thomas Desert Avatar asked Nov 29 '10 13:11

Thomas Desert


1 Answers

If this is still a problem for you.

I found several examples and discussions about this topic but the proper solution is quite simple.

In general hittest is called three times within a UIView or a UIScrollView - this results of traversing the view-hierarchy.

A quite simple and for me always suitable solution is:

implement the function hittest in the view you implemented

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

for me - all three function calls have always the same position - so just store the location in your local class.

in the .h File:

@interface MyScrollView : UIScrollView {
    CGPoint touchLocation_;
}

@property (nonatomic, readonly) CGPoint touchLocation;

in the .m File

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

- (BOOL)pointInside:(CGPoint)point withEvent:(UIEvent *)event{
// The point check you need    
    if(point.y != self.touchLocation.y){
        touchLocation_ = point;
    // The function call you need - just called once.
    }
    return [super pointInside:point withEvent:event];
}

This solution works for me in several projects quite well.

like image 193
Phil K. Avatar answered Oct 13 '22 13:10

Phil K.