Responding to touchesBegan in UIPickerView instead of UIView

I've been searching for a solution to this problem for over a week. I'm answering you even if you're question is over a year old hoping this helps others.

Sorry if my language is not very technical, but I'm pretty new to Objective-C and iPhone development.

Subclassing UIpickerView is the right way to do it. But you've to override the - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event method. This is the method called whenever you touch the screen and it returns the view that will react to the touch. In other words the view whose touchesBegan:withEvent: method will be called.

The UIPickerView has 9 subviews! In the UIPickerView class implementation - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event won't return self (this means the touchesBegan:withEvent: you write in the subclass won't be called) but will return a subview, exactly the view at index 4 (an undocumented subclass called UIPickerTable).

The trick is to make the - (UIView *)hitTest:(CGPoint)point withEvent:(UIEvent *)event method to return self so you have control over the touchesBegan:withEvent:, touchesMoved:withEvent: and touchesEnded:withEvent: methods.

In these methods, in order to keep the standard functionalities of the UIPickerView, you MUST remember to call them again but on the UIPickerTable subview.

I hope this makes sense. I can't write code now, as soon as I'm at home I will edit this answer and add some code.


Here is some code that does what you want:

@interface TouchDetectionView : UIPickerView {

}
- (UIView *)getNextResponderView:(NSSet *)touches withEvent:(UIEvent *)event;
@end
@implementation TouchDetectionView

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
    [hitTestView touchesBegan:touches withEvent:event];
}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
{
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
    [hitTestView touchesMoved:touches withEvent:event];
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
    [hitTestView touchesEnded:touches withEvent:event];
}

- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
    UIView * hitTestView = [self getNextResponderView:touches withEvent:event];
    [hitTestView touchesCancelled:touches withEvent:event];
}

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

- (UIView *)getNextResponderView:(NSSet *)touches withEvent:(UIEvent *)event
{
    UITouch * touch = [touches anyObject];
    CGPoint point = [touch locationInView:self];
    UIView * hitTestView = [super hitTest:point withEvent:event];

    return ( hitTestView == self ) ? nil : hitTestView;
}