Check which view sends gestureRecognizer - ios

This is what I want to do
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
if (touch.view != self.myView) {
NSLog(#"we went with no");
//don't let anything that's not myView fire the gesture recognizer
return NO;
}
NSLog(#"we went with yes");
return YES;
}
The problem is the code always chooses the path of "we went with no" no matter where I actually tap. How do I fix my if check?

If you're finding that your gesture recognizer action is firing when you're tapping outside of a specific view, you should double-check that you added the gesture recognizer correctly.
[self.myView addGestureRecognizer:[[UIGestureRecognizer alloc] initWithTarget:self action:#selector(someAction:)]];
If you still experience incorrect action fires, you could check the touch location.
if (CGRectContainsPoint(self.myView.bounds, [gesture locationInView:self.myView]))

Related

Stop UIWebTouchEventsGestureRecognizer from firing

Ok, I have a WKWebView with a big textarea inside it, and when I click on it, it fires this UIWebTouchEventsGestureRecognizer and shows the keyboard.
This behavior is correct. Problem is, when scrolling or panning from any other gesture, this UIWebTouchEventsGestureRecognizer is fired and the keyboard shows.
Is there any way to prevent that?
I'm using this to get the problematic gesture recognizer:
for (UIView* subview in self.subviews) {
// here comes the tricky part, desabling
for (UIView* subScrollView in subview.subviews) {
if ([subScrollView isKindOfClass:NSClassFromString(#"WKContentView")]) {
for (UIGestureRecognizer* gesture in [subScrollView gestureRecognizers]) {
if ([gesture isKindOfClass:NSClassFromString(#"UIWebTouchEventsGestureRecognizer")]) {
gesture.delegate = self;
gesture.delaysTouchesBegan = true;
gesture.delaysTouchesEnded = true;
[gesture requireGestureRecognizerToFail:scrollGesture];
}
}
}
}
}
requireGestureRecognizerToFail: doesn't work;
-(BOOL)gestureRecognizer:shouldRequireFailureOfGestureRecognizer:
also didn't work
The only thing that worked is returning false on this delegate method:
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
return false;
}
But obviously, now the keyboard will never show..
Resuming, I need the webview to get focus on taps, and to ignore pans and other gestures.
Any tips?
Did you this this one ?
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer

Disable Tap Gesture on Child View Controller? How to determine Is it a PanGesture or TapGesture?

All.
In my iOS 8.0 app.
In a Parent Child View architecture. By this code...
[self addChildViewController:slideTableViewController];
[self.view addSubview:slideTableViewController.view];
[slideTableViewController didMoveToParentViewController:self];
I have implemented TapGesturerecognizer & PanGesturerecognizer on Base View Controller.
So, that it can recognise Pan(Dragging) and Tap. I need both gestures on my BaseView.
Just do not want Tap Gesture on SlideView.
As I want to execute didSelectRowAtIndexpath method on child view,
Solution:
Answer for Question 1:
Many StackOverflow answers have the same funda..
Disable Tap gesture when your touch encounters child view.
if([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]){
if(CGRectContainsPoint(slideTableViewController.view.frame,[touch locationInView:self.view])){
return NO;
}
}
Answer for Question 2:
How to determine Is it a PanGesture or TapGesture ?
For each gesture type the delegate method will call
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
If you have implemented two gestures in your view, pan gesture and touch gesture,
This method will call 2 times, 1 time for pan gesture and 1 time for tap gesture.
So, in this method you can check like isKindOfClass method.
Thank you very much for helping......
Just set tapGesture.cancelsTouchesInView = YES;
You can implement the gesture's delegate method in your baseViewController :
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizershouldReceiveTouch:(UITouch *)touch {
return touch.view == self.view;
}
OR
//If it is a Tap Gesture and Your touch intersects with a perticular View, For that we have this method.
if([gestureRecognizer isKindOfClass:[UITapGestureRecognizer class]]){
if(CGRectContainsPoint(slideTableViewController.view.frame,[touch locationInView:self.view])){
return NO;
}
}
I have done this in UIViews I hope this could help you:
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch *touch = [touches anyObject];
[touch locationInView:self.view];
if(touch.view == self.topView )
{
//just return
}
if(touch.view == SOSTopView )
{
//just return
}
}
Looks like you should implement this method of UITableViewDelegate:
- (NSIndexPath *)tableView:(UITableView *)tableView
willSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// you can add some logic here
return nil;
}
This will prevent from selecting any rows.
Isn't there a userInteractionEnabled property that you can make use of? So you could do the following:
slideTableViewController.userInterationEnabled = NO;

UIGestureRecognizer receives touch but doesnt execute action

I have an MPMoviePlayerController which I add to a view with:
MPMoviePlayerController *mpc = INIT and other stuff
[self.view addSubview:mpc.view];
In IB I've hooked up a tap gesture recognizer to a selector called showhide:.
I have a toolbar on the screen, and when it's touched it prevents the gesture from going through with:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
CGPoint touchedPoint = [touch locationInView:self.view];
if (self.controlsVisable) {
BOOL inbar = CGRectContainsPoint(self.controlBar.frame, touchedPoint);
NSLog(#"inbar? %d", inbar);
return !inbar;
}
return YES;
}
And that works perfectly. If I tap in the bar, it prints "inbar? 1" and otherwise it prints "inbar? 0". So clearly it is getting the touches. But it never executes showhide:.
To clarify, showhide: should fire only when I press outside of the bar. Also, regardless of if I tap inside or outside of the bar, showhide: never fires

tableView is hiding due to a gestureRecognizer before it can execute didSelectRowAtIndexPath

I am trying to handle tableViewCell's being tapped, but the problem is that this is a "temporary tableView". I have it coded so that it will appear while the user is editing a UITextField, but then I set up a gesture recognizer to set the tableview to hidden as soon as the user clicks somewhere away from the UITextField.
I have the gesture recognizer set up as follows:
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
initWithTarget:self
action:#selector(dismissKeyboard)];
[tap setCancelsTouchesInView:NO];
[self.view addGestureRecognizer:tap];
However, dismissKeyboard is called before didSelectRowAtIndexPath is called, and so the TableView that I want to handle the event on becomes hidden and therefore this function is never called.
My question is: Does anybody have ideas of how to get around this, so that didSelectRowAtIndexPath will execute before the tableView hides? I had one idea to somehow see if the tableView is where the tap is coming from, and if so, then don't execute the "hide tableView" line within dismissKeyboard. Is this possible?
Sorry, but I am new to iOS dev, so thank you for any advice!
You should be able to do this by making your view controller the tap gesture's delegate and denying it any touches that are inside the table view. Here is a starting point:
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gesture shouldReceiveTouch:(UITouch *)touch
{
//Assuming your table view is a direct subview of the gesture recognizer's view
BOOL isInsideTableView = CGRectContainsPoint(tableView.frame, [touch locationInView:gesture.view])
if (isInsideTableView)
return NO;
return YES;
}
Hope this helps!
You could set yourself as a delegate to the UITapGestureRecognizer and cancel the gesture when the user taps within the tableView.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch
{
//You can also (and should) check to make sure the gestureRecognizer is the tapGestureRecognizer
if (touch.view == tableView)
{
return NO;
}
else
{
return YES;
}
}
To better fit what you need, judge if your search bar is first responder.
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gesture shouldReceiveTouch:(UITouch *)touch
{
BOOL isInsideTableView = CGRectContainsPoint(yourTabelView.frame, [touch locationInView:gesture.view]);
if (isInsideTableView && ![yourSearchBar isFirstResponder])
return NO;
return YES;
}

Prevent annotation deselected when overlay tapped

On my mapview I draw polygon overlays that belong to a specific annotation. I want that annotation to be selected when the overlay is tapped. My first attempt was to add a UITapGestureRecognizer to the mapview, test whether the tapped point is inside a polygon and perform [mapView selectAnnotation:myAnnotation] on success. The problem is that after this, the mapview decides there was a tap not on any annotations, so it deselects the annotation again.
My question is how to best prevent this from happening, I don't seem to be able to find a nice solution. What I have tried:
Create a new UIGestureRecognizer subclass that recognizes just taps inside overlays, then iterate through mapView.gestureRecognizers and call requireGestureRecognizerToFail on each. However, the mapview does not expose any recognizers through its property.
Return YES for shouldBeRequiredToFailByGestureRecognizer in my custom recognizer for any other recognizer that isKindOfClass tap recognizer. However, there still seems to be another recognizer that is not passed in there.
Place a transparent view on there and do the polygon check in pointInside:withEvent, but does also blocks any other gestures besides only taps.
EDIT:
After poking around a bit more, I have code that is almost working, of which I know where it goes wrong. I have a custom recognizer as before. In its delegate I do:
- (BOOL)gestureRecognizer:(UIGestureRecognizer*)gestureRecognizer
shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer*)otherGestureRecognizer
{
[otherGestureRecognizer requireGestureRecognizerToFail:gestureRecognizer]; // can possibly do this in custom recognizer itself instead
return YES;
}
Now taps inside polygons successfully prevent deselection. However, when I then do:
- (void)mapView:(MKMapView *)mapView didSelectAnnotationView
{
// displayRegion is chosen to center annotation
[mapView setRegion:self.displayRegion animated:YES];
}
it breaks again, and the annotation gets deselected again..
It seems we have the same problem ( a little different: i'm tryng to select manually an annotation in a gesture recognizer )
I'm doing so ( and it works, but it seems to complex to me , feel free to ask more if it's not clear ):
i'm working with a long pressure event :
...
_lp1 = [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(handleOverlayLp1:)];
((UILongPressGestureRecognizer*)_lp1).minimumPressDuration = 0.05;
_lp1.delegate = self;
[_mapView addGestureRecognizer:_lp1];
...
I collect all gesture recognizers in a global var :
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if (_gestureRecognizers==nil)
_gestureRecognizers = [NSMutableSet set];
[_gestureRecognizers addObject:otherGestureRecognizer];
return YES;
}
// when i recognize gestures, disable everything and call an asyncrhronous task where i re-enable
- (void)handleOverlayLp1:(UIGestureRecognizer*)recognizer
{
// Do Your thing.
if (recognizer.state == UIGestureRecognizerStateBegan)
{
BOOL found=NO;
...
if (found) {
// disable gestures, this forces them to fail, and then reenable in selectOverlayAnnotation that is called asynchronously
for (UIGestureRecognizer *otherRecognizer in _gestureRecognizers) {
otherRecognizer.enabled = NO;
[self performSelector:#selector(selectOverlayAnnotation:) withObject:polyline afterDelay:0.1];
}
}
}
}
- (void)selectOverlayAnnotation: (id<MKAnnotation>) polyline
{
[_mapView selectAnnotation:polyline animated:NO];
for (UIGestureRecognizer *otherRecognizer in _gestureRecognizers) {
otherRecognizer.enabled = YES;
}
}

Resources