UIButton responds to UIPanGestureRecognizer on top of it - objective-c

I just added a UIView with UIPanGestureRecognizer on top of my view.
The view has several UIButtons which respond to touchUpInside events.
What's weird is that ever since I brought the UIPanGestureRecognizer, when panning, if the UIButton is right underneath the "Panning view", the button would trigger which is not what I am after.
Of course I could make a BOOL flag for "panning", so that the button won't fire, but it seems to me like bad engineering and surely something I am missing. I guess after the first touch, both views intercept the event.
Is it possible to overcome this?
Thanks

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer
shouldReceiveTouch:(UITouch *)touch {
if ([touch.view isKindOfClass:[UIButton class]]) {
return NO;
}
return YES;
}
use this method to differentiate GestureRecognizer and Button Acton.
Hope this helps you.

Not sure if this help
[[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePanned:)];
- (void)handlePanned:(UIPanGestureRecognizer*)thePanner{
if (thePanner.state == UIGestureRecognizerStateChanged ){
//disable button
}else if (thePanner.state == UIGestureRecognizerStateEnded) {
//enable button
}else if ( thePanner.state == UIGestureRecognizerStateFailed ){
//enable button
}
}

you can sort-out your problem by following two tactics:-
1)When adding the gesture in your required view, be sure that it will not added with un-required view, in this case is your UIButton, &;
2)At the method/delegate where you handle the case of detecting the gesture, ie what gesture do, before the implementation you assure that this is not the UIButton.
If you insist, I'll try for sample code.
Have a good day ahead. :)

Related

How to recognize rubbing gesture?

I was wondering how to create some type of recognizer for a rubbing gesture.
You can see this gesture in Talking Tom Cat app and I would love to have this gesture in my clone of the app. Could you please guide me a little?
As I understand it, it is probably a swipe up and swipe down, however I don't know how to implement it the same as in the Talking Tom Cat - that means, playing animation and sound while I am rubbing the character. (I know how to play sound and animation, just don't know how to implement it with this gesture)
Also I am not sure, if it is better done by using UIGestureRecognizer or touchesBegan, Moved, Ended etc.
You could try something like this:
first add gesture recognizer where you are setting up the view.
[myView addGestureRecognizer:[[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)]];
Then add code to handle gestures.
-(void)handlePan:(UIGestureRecognizer *)sender
{
if(sender.state == UIGestureRecognizerStateBegan) {
[self startAnimation];
} else if (sender.state == UIGestureRecognizerStateEnded) {
[self stopAnimation];
}
}
hope that helps.

How to stop UIPanGestureRecognizer from recognizing taps

On one of the UIViewControllers of my iPhone app, I have a UIPanGestureRecognizer attached so that when the user swipes to the left or to the right the app advances or goes back one screen. However, the problem is that when the user taps (rather than swipes) on the screen it still advances. How can I stop this from happening. I have pasted the relevant code below:
-(void) addGestureRecognizer
{
UIPanGestureRecognizer *pan;
pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(swipeRecognized:)];
[pan setMinimumNumberOfTouches:1];
[self.view addGestureRecognizer:pan];
}
-(void) swipeRecognized: (UIPanGestureRecognizer *) recognizer
{
if(recognizer.state != UIGestureRecognizerStateBegan) return;
CGPoint velocity = [recognizer velocityInView:self.view];
if(velocity.x > 0)
{
[self.navigationController popViewControllerAnimated:YES];
}
else
{
#try
{
[self performSegueWithIdentifier:NEXT_STEP_SEGUE sender:self];
}
#catch (NSException *exception)
{
//Silently die...muhaha
}
}
}
I would suggest using a UISwipeGestureRecognizer for swipes. Is there a particular reason you're use a pan?
With a UISwipeGestureRecognizer you can specify for which direction it should recognize the gesture.
It's also better for your users, to use the appropriate gestures. That way, they'll feel right at home :)
You should either use a UISwipeGestureRecognizer, as suggested by fguchelaar, or use the translationInView: method to figure out how far the user has actually moved the finger (for taps, that should be near zero).
You also shouldn't return early if the state is not UIGestureRecognizerStateBegan (first line in your method), otherwise your method will only get called once, when the gesture begins, but not during the gesture. If that's what you actually want, a UISwipeGestureRecognizer is all you need. The benefit of the pan gesture recognizer is mostly that you can track the user's finger and provide direct feedback (like moving the view while the finger is still down).

MFSideMenu full size pan gesture

I use MFSideMenu in my application, and i can show the menu using a pan gesture on the navigation bar only. I would like it to work on the whole screen, like on the facebook app.!
I've tried changing this line (l.39 in MFSideMenuManager.m)
[controller.navigationBar addGestureRecognizer:recognizer];
to this :
[controller.view addGestureRecognizer:recognizer];
but it just won't work.
Do you have any idea of what i should edit for it to work?
Thank you for your help
I finally succeeded making it work. The gesture is actually already implemented but working only if the menu is hidden. We have to remove 2 conditions to make sure it works both ways
There are two lines to edit in the MFSideMenuManager.m
In the gestureRecognizerShouldBegin: method
if([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
if([gestureRecognizer.view isEqual:self.navigationController.view] &&
self.navigationController.menuState != MFSideMenuStateHidden) return YES;
becomes
if([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
if([gestureRecognizer.view isEqual:self.navigationController.view]) return YES;
In the navigationControllerPanned: method, just remove the if line
- (void) navigationControllerPanned:(id)sender {
if(self.navigationController.menuState == MFSideMenuStateHidden) return;
[self handleNavigationBarPan:sender];
}
becomes
- (void) navigationControllerPanned:(id)sender {
[self handleNavigationBarPan:sender];
}
And it works!
It is not a really good practice to edit a library, but it is easy if you want to go further to add a boolean option to MFSideMenu to make it configurable.
I don't know the MFSideMenuManager but if the bar is draggable I expect it to have a UIPanGestureRecognizer with a line
[self.navigationController.navigationBar addGestureRecognizer:gestureRecognizer];
So what you do is replace the navigation bar with the view for the whole navigation controller
[self.navigationController.view addGestureRecognizer:gestureRecognizer];

Handling Multiple Gestures on a View

Is there any way to detect a single tap vs. a scrolling gesture on a UIWebView?
I have a UIWebView, that contains rich text that many times, scrolls, if there is a lot of text content. I need to add a new feature that will allow the user to tap the UIWebView to get different content.
The problem is, my solution for this was to place a clear custom button on top of the UIWebView, which handles the tap but kills the scrolling feature. How do the cool kids do this type of thing?
Thanks
I solved this with a gesture recognizer. This eliminates the need for the UIButton overlay altogether.
//Handle taps on the UIWebView
self.singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(**tapDetected:**)];
singleTap.numberOfTapsRequired = 1;
singleTap.delegate = self;
[self.readAboutItView addGestureRecognizer:singleTap];
//Set up the event handler
- (IBAction)**tapDetected:**(UIGestureRecognizer *)sender {
//Do something with the content
[self webViewTouched:self];
}
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
return YES;
}
-(BOOL) gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;
}

How to replace TouchesBegan with UIGestureRecognizer

here's the problem:
I'd like to move to using UIGestureRecognizer in my Apps.
For this reason I'd like to ditch TouchBegan/TouchEnded event's from my views.
However I don't understand how to manage when the touch began (user puts its finger on the screen) with UIGestureRecognizers.
The simplest one is UITapGestureRecognizer but the selector associated gets fired only when the TapGesture is completed (Well... it makes completely sense of course). But still the problem remains: how can I stop using touchesBegan and get that event anyway from UIGestureRecognizer?
Thanks!
Here is an example:
//Pan gesture
recognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(handlePan:)];
((UIPanGestureRecognizer *)recognizer).minimumNumberOfTouches = 3; //number of fingers
recognizer.delegate = self;
[self.view addGestureRecognizer:recognizer];
[recognizer release];
- (void)handlePan:(UIPanGestureRecognizer *)recognizer
{
if (recognizer.state == UIGestureRecognizerStateBegan)
{
//do something
} else if (recognizer.state == UIGestureRecognizerStateEnded)
{
//do something
}
}
Also implement UIGestureRecognizerDelegate in .h file. May be you need to do self.view.userInteractionEnabled = YES depending on the view you're using. e.g., if it's UIImageView, the you need to set userInteractionEnabled = YES, default is NO
For what you are tryin ti do you can't. The gesture recoginizers are for high level gestures so they behaive the same across all apps (think swipes, the timing required for a double tap, etc). For low level control and to do things that the recognizers can't you will still have to implement logic in touchesbegan, touchesEnded, etc.
Why not implement your own touchesBegan in a UIGestureRecognizer subclass -- intercept the message, extract the information you'd like, and then pass the message along to super's touchesBegan?