Apparently iOS 6 tries to automatically handle the situation when you have a gesture recognizer and a UIButton
in the same place, being activated for the same gesture.
This new automatic handling solves the issue when you want to click the button instead of activating the gesture recognizer, but creates a new problem when you want the gesture recognizer to act.
In iOS 5 you could implement:
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
to transfer the action to the UIButton
when in a conflict.
This doesn't seem to work in iOS 6. Also, inverting the behavior of this method (because now the UIButton
has the priority instead of the gesture recognizer) won't work.
Complete method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass:[UIControl class]]){
return NO;
}
return YES;
}
I've done this to workaround the issue, change it as you see fit:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
[self MyCommonSelector];// this will work for ios 5
return Yes;
}
Add target in button where you declare so this will call in iOS 6:
[self.myButton addTarget:self action:@selector(MyCommonSelector)
forControlEvents:UIControlEventTouchUpInside];
Do your stuff in this method which will also be called on button tap and from the gesture you need to call:
-(void)MyCommonSelector
{
//Do your stuff here what you want to do with Gesture too.
}
Although i don't know why you would put UIButtons there if you don't want them to be tapped, you can prevent subviews from receiving touches by overriding the -hitTest:withEvent:
method of your containing view.
-hitTest:withEvent:
by default returns the "farthest descendant of the receiver in the view hierarchy (including itself) that contains a specified point", so by default, when tapping one of the buttons, your containing view would return the button.
Your implementation should look something like this:
- (UIView *)hitTest:(CGPoint)aPoint withEvent:(UIEvent *)event {
if ([self pointInside:aPoint]) {
return self;
} else {
return nil;
}
}
So if your container view this is being called on contains the point of the touch, it returns itself and the gesture recognizer attached to it will get the touch.
Because this implementation never returns any subview, none of the UIButtons will ever get a chance to respond to the touches.
I know it seems simplistic, but have you considered setting the UIButton's userInteractionEnabled property to "NO"? That should remove it automatically from the hit testing and gesture recognition system.