The following code in my view controller results in an EXC_BAD_ACCESS at the touch.view call:
- (BOOL)handleSingleTap:(UITapGestureRecognizer *)recognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass:[UIControl class]]) { // <<<< EXC_BAD_ACCESS HERE
// we touched a button, slider, or other UIControl
return NO; // ignore the touch
}
[self.view endEditing:YES]; // dismiss the keyboard
return YES; // handle the touch
}
touch appears to be a zombie. Specifically, touch is set to an address, and the debugger thinks that's a UITouch pointer, but it doesn't have any properties:
This did not happen in iOS 4.x. So iOS 6 bug or my fault?
The gesture recognizer is set up as follows (in the ViewController):
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:shouldReceiveTouch:)];
[tapRecognizer setDelegate:self];
[tapRecognizer setNumberOfTapsRequired:1];
[tapRecognizer setNumberOfTouchesRequired:1];
tapRecognizer.cancelsTouchesInView = NO;
[self.view addGestureRecognizer:tapRecognizer];
[tapRecognizer release];
UPDATE/SOLUTION:
Thanks to Rob for pointing out the user error on my part. Not only that, but I don't actually need the TapRecognizer since I just want to know a touch happened.
Here's the correct code to dismiss the on-screen keyboard with a touch anywhere but in a UIControl:
In the ViewController's viewDidLoad:
UIGestureRecognizer *myRecognizer = [[UIGestureRecognizer alloc] init];
[myRecognizer setDelegate:self];
myRecognizer.cancelsTouchesInView = NO;
[self.view addGestureRecognizer:myRecognizer];
[myRecognizer release];
And:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass:[UIControl class]]) {
// we touched a button, slider, or other UIControl
return NO; // ignore the touch
}
[self.view endEditing:YES]; // dismiss the keyboard
return YES; // handle the touch
}
You're using a method, handleSingleTap:shouldReceiveTouch:, whose signature does not conform to the permissible signatures. See the Overview section of UIGestureRecognizer Class Reference. It should only have the one parameter, the gesture recognizer.
I think you may be confusing the handler with the UIGestureRecognizerDelegate protocol method gestureRecognizer:shouldReceiveTouch:.
Related
i am creating drawer
self.isShowMenuVC = NO;
_menuView = [MenuViewController viewController];
[self.menuView setDelegate:self];
[self addChildViewController:self.menuView];
[self.menuView.view setFrame:CGRectMake(-kMenuTableWidth, 0, kMenuTableWidth, self.view.frame.size.height)];
[self.view addSubview:self.menuView.view];
[self.menuView didMoveToParentViewController:self];
UITapGestureRecognizer *outsideTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(outsideTapped:)];
[self.view addGestureRecognizer:outsideTap];
outsideTap.delegate = self;
and when button tap i just set frame of _menuView.view to behave like a drawer
what i want is to detect touch outside of drawer but i am not able to do it
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if (touch.view == self.menuView.view) {
NSLog(#"Touch Drawer");
} else {
NSLog(#"Touch Outside");
}
return YES;
}
but it is always show Touch Outside"
i am missing something but don't know what thanks in advance
Also try with 2 gesture but not working because one gesture in self.view so, when i tap in drawer method call 2 times.
for that i tried to disable one gesture, still calling two times
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if (gestureRecognizer == self.touchInDrawer) {
NSLog(#"Touch in drawer");
[self.touchOutSideDrawer setEnabled:NO];
} else {
NSLog(#"Outside");
[self hideMenuView];
}
return YES;
}
The UITapGestureRecognizer cannot detect the touch outside the view which it belongs to.
You need to create another UITapGestureRecognizer and add them to self.menuView.view.
Also you can make two #property for your gesture recognizers and check them inside method:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if (gestureRecognizer == self.firstGesture) {
NSLog(#"Touch in first gesture");
} else {
NSLog(#"Touch in another gesture");
}
I have solve this issue with adding two gesture
#property (strong,nonatomic) UITapGestureRecognizer *touchInDrawer;
#property (strong,nonatomic) UITapGestureRecognizer *touchOutSideDrawer;
as per #Eugene Zaychenko's Answer but there is still problem because delegate method calling two times
also i can't [self.touchOutSideDrawer setEnabled:NO]; when touch in drawer tapped, because after that it will remove from the view and never executed again if [self.touchOutSideDrawer setEnabled:YES];
but most interesting thing is
_touchInDrawer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(outsideTapped:)];
[self.menuView.view addGestureRecognizer:self.touchInDrawer];
self.touchInDrawer.delegate = self;
_touchOutSideDrawer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(outsideTapped:)];
[self.view addGestureRecognizer:self.touchOutSideDrawer];
self.touchOutSideDrawer.delegate = self;
outsideTapped method calling only one time so i shifted my all code there and is working
- (void) outsideTapped:(UITapGestureRecognizer *)gestureRecognizer {
if (gestureRecognizer == self.touchOutSideDrawer) {
// [self.view removeGestureRecognizer:self.touchOutSideDrawer];
[self hideMenuView];
NSLog(#"Outside");
} else {
NSLog(#"Touch in drawer");
// [self.touchOutSideDrawer setEnabled:NO];
}
}
I need to dismiss the presentViewController when click the outside the controller, I'm using the following code
UITapGestureRecognizer *tapBehindGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapBehindDetected:)];
[tapBehindGesture setNumberOfTapsRequired:1];
[tapBehindGesture setCancelsTouchesInView:NO];
[self.view.window addGestureRecognizer:tapBehindGesture];
- (void)tapBehindDetected:(UITapGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateEnded)
{
CGPoint location = [sender locationInView:nil]; //Passing nil gives us coordinates in the window
//Then we convert the tap's location into the local view's coordinate system, and test to see if it's in or outside. If outside, dismiss the view.
if (![self.view pointInside:[self.view convertPoint:location fromView:self.view.window] withEvent:nil])
{
// Remove the recognizer first so it's view.window is valid.
[self.view.window removeGestureRecognizer:sender];
[self dismissViewControllerAnimated:YES completion:nil];
}
}
}
its working fine for me, but i had problem in another view. Inside the view controller I add UITapGestureRecognizer to vwHeaderview.
UITapGestureRecognizer *addNewContactsingleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
[vwHeaderview addGestureRecognizer:addNewContactsingleFingerTap];
- (void)handleSingleTap:(UIGestureRecognizer *)gestureRecognizer
{
//Some code
}
If I click the vwHeaderview It call the "tapBehindDetected", I wont call "handleSingleTap".
If I comment above "tapBehindGesture" Its working fine. But I need both to work. any help
I add delegate to vwHeaderview and use following function & its working fine for me...
UITapGestureRecognizer *addNewContactsingleFingerTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
addNewContactsingleFingerTap.delegate = self;
[vwHeaderview addGestureRecognizer:addNewContactsingleFingerTap];
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
Facing trouble with UITableViewCell.I tried to get the data of selected UITableViewCell. Initially it is working good but after the UITapGestureRecognizer its making this trouble. The table i've used is assigned to the one subview even few buttons are not taking the action at first click. I am facing this trouble exactly after adding the UITapGestureRecognizer.
tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(didTapAnywhere:)];
[tapRecognizer setNumberOfTapsRequired:1];
[tapRecognizer setNumberOfTouchesRequired:1];
[self.view addGestureRecognizer:tapRecognizer];
[self.scrolling addGestureRecognizer:tapRecognizer];
[self.notesView addGestureRecognizer:tapRecognizer];
-(void)didTapAnywhere: (UITapGestureRecognizer*) recognizer {
[ageview removeFromSuperview];
[contiView removeFromSuperview];
[CountryTableview removeFromSuperview];
[notesView endEditing:YES];
[self.view endEditing:YES];
}
Your Tap Guesture is cancelling the touch guesture to your cell and your Buttons, make sure that the view to which you are assigning a tap guesture does not overlap the buttons which would result in cancellation of touch events
Did you implement delegate method of UIGestureRecognizerDelegate
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
UIView *view = (UIView *)touch.view;
if([view isKindOfClass:[<YOUR_BUTTON> class]]) {
return NO;
}
return YES;
}
OR you can give some tag to button like following
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
UIView *view = (UIView *)touch.view;
if(view.tag == 10000) {
return NO;
}
return YES;
}
I've looked around on Stack for solutions to this and found quite a few results, but I'm still unable to fix my problem, mainly because I'm working on a CCNode opposed to some UIView.
Anyways, my CCButton works find without the UITapGestureRecognizer, but when I implement it, it overrides my button press. Obviously I would like to avoid this.
My code is below. My swipe gestures work perfectly, but the tap interferes with my button. I'm not sure if I'm adding the gesture recognizer to the wrong view, because - (BOOL)gesturerecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch never runs, which is where I would put in my exception. If anyone can give me some code/ideas on how to fix this it would be greatly appreciated, thanks!
-(void)didLoadFromCCB
UITapGestureRecognizer * gridTapped = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(gridTapped)];
[[[CCDirector sharedDirector] view] addGestureRecognizer:gridTapped];
//this works totally fine
UISwipeGestureRecognizer * swipeLeft= [[UISwipeGestureRecognizer alloc]initWithTarget:self action:#selector(swipeLeft)];
swipeLeft.direction = UISwipeGestureRecognizerDirectionLeft;
[[[CCDirector sharedDirector] view] addGestureRecognizer:swipeLeft];
}
-(void)gridTapped {
//this works!
CCLOG(#"Grid tapped");
}
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
//This never runs
CCLOG(#"gesture recognized");
if ((touch.view == mainMenuButton)) {
return NO;
}
return YES;
}
Try setting the UITapGestureRecognizer delegate:
gridTapped.delegate = self;
You'll need to declare the VC class as implementing <UITapGestureRecognizerDelegate>
This question already has answers here:
UIButton not calling action in iOS 5 but works in iOS 6
(2 answers)
Closed 9 years ago.
For some reason, my UITapGestureRecognizer is not calling it's method when I tap a UIButton. What's really weird is that I used breakpoints in Xcode to make sure that the gestureRecognizer:shouldReceiveTouch: method is returning YES. The gesture should be calling it's method, but it isn't. I have cancelsTouchesInView set to YES, but it doesn't seem to do anything.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass: [UIButton class]] && !editingTaskName)
return NO;
else if ([touch.view isKindOfClass: [UITextField class]])
return NO;
return YES; // handle the touch
}
Here's the code where I set up all my gesture recognizers. Maybe the others are interfering with my tap gesture.
UILongPressGestureRecognizer *longPress = [[UILongPressGestureRecognizer alloc] initWithTarget: self action: #selector(longPress:)];
[longPress setMinimumPressDuration: 0.3];
[longPress setDelaysTouchesBegan: YES];
[self setLongPressGesture: longPress];
[[self tableView] addGestureRecognizer: longPress];
UITapGestureRecognizer *backToTableView = [[UITapGestureRecognizer alloc] initWithTarget: self action: #selector(backTapRecognized:)];
[backToTableView setCancelsTouchesInView: YES];
[backToTableView setDelegate: self];
[backToTableView setEnabled: NO];
[self setBackTapGesture: backToTableView];
[[self tableView] addGestureRecognizer: backToTableView];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget: self action: #selector(hideShowEditing:)];
[tap setCancelsTouchesInView: YES];
[tap setDelegate: self];
[self setEditTap: tap];
[[self tableView] addGestureRecognizer: tap];
A button has its own tappability, so there's a conflict between the button and the gesture recognizer. In iOS 6, button wins; the gesture recognizer is thus prevented from recognizing.
In iOS 6, there is a UIView gestureRecognizerShouldBegin: method. The UIButton returns NO (that's built-in), so that's the outcome of the conflict.
This takes even higher priority than your gestureRecognizer:shouldReceiveTouch:.
Try setting the numberOfTapsRequired property of your UITapGestureRecognizer. Something like this should suffice:
tap.numberOfTapsRequired = 1;
Max