Disabling UIPinchGestureRecognizer with setEnabled:NO - iphone

I have a pinch gesture recognizer attached to my scrollView (one on top of the default one). I'm trying to enable it and disable it at certain zoom levels but it is not working. I use the commands:
[self.pinchGesture setEnabled:NO];
and
[self.pinchGesture setEnabled:YES];
to enable and disable the pinch gesture. I am trying to debug it and I use this code to print out the description of my gestures:
NSArray *gestures = [self.scrollView gestureRecognizers];
for (UIGestureRecognizer *gesture in gestures) {
NSLog(#"%s, gesture: %#", __FUNCTION__, [gesture description]);
}
I see that for my custom gesture it looks like:
gesture: <UIPinchGestureRecognizer: 0x88a62d0; state = Possible; enabled = NO; view = <UIScrollView 0x880c360>; target= <(action=handlePinch
So even though it is set to enabled = NO, the pinch still calls the handlePinch: method. Is there a reason for this? Or do I need to use the [self.scrollView setGestureRecognizers:<#(NSArray *)#> to remove that pinch gesture? If I am to go with that approach, do I have to loop through my gestures for the scrollView, save references to those, than set those so I don't set back my custom pinch gesture? Thanks.

The enabled scrollview just does that: enables and disables the scrollview. The Gesture Recognizers are a different animal, that are kind of latched into your scrollview, but behave almost independently. Why not remove the target for the gesture instead of disabling, then add the target back in when enabling? Alternatively, set a boolean that your target method checks and ignores the gesture when the boolean is YES.

Related

Pass taps through a UIPanGestureRecognizer

I'd like to detect swipe on the entire screen, however, the screen contains UIButtons, and if the user taps one of these buttons, I want the Touch Up Inside event to be triggered.
I've create a UIView on the top of my screen, and added a UIPanGestureRecognizer on it to detect the swipe, but now I need to pass the gesture through that view when I detect that it's a tap rather than a swipe.
I know how to differentiate the gestures, but I've no idea on how to pass it to the view below.
Can anyone help on that? Thanks!
Thanks for your answer. The link helped me to solve part of my problem.
I've set the buttons as subviews of my gestureRecognizer view and I can now start a swipe from one of the buttons (and continue to use the buttons as well). I managed to prevent the buttons to go to the "down" state by using the following code :
UIPanGestureRecognizer *swipe = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(swipeDetected:)];
swipe.maximumNumberOfTouches = 1;
swipe.delaysTouchesBegan =YES;
swipe.cancelsTouchesInView = YES;
[self.gestureRecognitionView addGestureRecognizer:swipe];
there is a BOOL property of UIGestureRecognizer cancelsTouchesInView. default is yes. set it to NO , and the touches will pass thru to the UIView
also have a look at the solution for this question
If you want to prevent the recognizer from receiving the touch at all, UIGestureRecognizerDelegate has a method gestureRecognizer:shouldReceiveTouch: you can use:
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
// don't override any other recognizers
if (gestureRecognizer != panRecognizer) {
return YES;
}
CGPoint touchedPoint = [touch locationInView:self.someButton];
return CGRectContainsPoint(self.someButton.bounds, touchedPoint) == NO;
}

UITextField stops UIGestureRecognizer from working

I've got a view containing subviews of various types on it. At one point, I would like to disable all interactions with the view and subviews, and register instead taps from a gesture recognizer I place on the whole view:
tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:revealController action:#selectorrdoSomething:)];
tapGestureRecognizer.cancelsTouchesInView = YES;
While it sort of works, the view below still interacts to all the touches. I then tried adding:
tapGestureRecognizer.delaysTouchesBegan = YES;
tapGestureRecognizer.delaysTouchesEnded = YES;
It now works EXCEPT - when I tap over a UITextField, this receives the touch INSTEAD of the gesture recognizer. Why is this, how can I stop it? Any help is much appreciated :)
Sounds like what you want to do is set the view you don't want receiving the touches .userInteractionEnabled property to FALSE. Or I am misunderstanding something.
yourView.userInteractionEnabled = FALSE;

UIGestureRecognizer with both setDelegate and action

I'm trying to add a UIPanGestureController to my UITableView so I can detect whether the user is manually panning or they just gave an initial kick and watch the view scroll by itself. The reason is that I want to snap to a cell as soon as the scrolling slows down (imagine a wheel of fortune). Of course I don't want to snap when the user is panning manually.
However, I can either use the gesture controller (and set my "is scrolling manually" variables accordingly") OR scroll the view.
Using TouchBegin events instead of the gesture recognizer introduces new problems, so that's not really an option.
First I changed the table view to include the UIGestureRecognizerDelegate.
After initializing the view, I then do...
panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:#selector(panTableView:)];
[panGestureRecognizer setDelegate:self];
[self.view addGestureRecognizer:panGestureRecognizer];
I implement the Begin function, to set a BOOL:
- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer
{
isPanning = YES;
return NO;
}
Always returning NO should make sure that the gesture recognizer is never active, since I want (and need) to use the table view's own scroll methods.
Problem: my action "panTableView" is never called.
If I don't set the delegate, the action is called, but I can't scroll, since the gesture recognizer catches all my touches.
I already looked into the targets. After setting the delegate, the gesture recognizer's view and delegate pointers are the same as self.view, the action still targets self with the right selector.
try
- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer
{
isPanning = YES;
return YES;
}
and implement this
-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
return YES
}

checking for a specific gesture recognizer

I'm looking at some existing code that adds a pinchGestureRecognizer at a specific zoom level of a scrollView. (Like when the scrollView.zoomScale > 10). At this zoom level, the pinch gesture does some special handling with a (handlePinch: selector)on the scrollView on the pinch.
I'm tasked to have a slider emulate the zooming of the scrollView so the user doesn't have to use two fingers to pinch all the time to zoom. I'd like to add the pinchGesture when my zoomScale is > 10 for the scrollView to get the same special handling. I don't want to add two of the same gestureRecognizers since I am assuming that if I blindly add it when the zoomScale > 10, I'm going to get unwanted behavior. I don't know how to check for a specific gesture in this case.
I basically want to do something like this:
- (IBAction)sliderChanged:(id)sender {
UISlider *slider = (UISlider *)sender;
if (slider.value > .6 && slider.value < .8) {
// check for pinch gesture
// I thought I could get the NSArray of gestures from my self.scrollView and check if it's empty, but there are other gestures are already attached to the scrollView.
// I thought I could also try self.scrollView respondsToSelector:#selector(handlePinch:), but I don't think that works.
//self.scrollView addGestureRecognizer
}
if (yourPinchRecognizer == nil) {
// do something
}
This has worked for me with the app I am working on.

Dragging UIButtons in UIScrollView?

I have a scrollview in my Main view and I have three subviews on my scrollview. And I have UIButtons in all my subviews.
Now, I want to drag those buttons from one subview to another subview (while dragging the buttons, the scrollview should not scroll).
How do I do this?
I'm not completely sure if this snippet works for this particular case (an UIControl inside a UIScrollView), but my understanding of UIResponder chain suggests me that it should :)
- (void)viewDidLoad { // or wherever you initialize your things
...
// Add swipe event to UIButton so it will capture swipe intents
UIPanGestureRecognizer *panGR = [[UIPanGestureRecognizer alloc] init];
[panGR addTarget:self action:#selector(panEvent:)];
[button addGestureRecognizer:panGR];
[panGR release];
}
- (void)panEvent:(id)sender {
button.center = [sender locationInView:self.view];
}
If this works (can't test it right now, but it did work for me in a similar situation), then you should add more code to handle the drag & drop related events (maybe disable Clip Subviews option in the UIScrollView, add the button to the new superview if the location intersects with the CGRect of the destination, return the button to the original location if it doesn't, etc).
So, what's happening in those lines? When you begin touching the UIButton, the order doesn't get to the UIScrollView because the event could follow as a touch event (handled by the UIButton), or as a pan event (handled by the UIScrollView). When you move your finger, the event is dismissed by the UIButton's responder because there's no Gesture Recognizer that knows how to proceed if the finger is moved.
But when you add a Gesture Recognizer to the UIButton who actually knows what to do when the finger is moved, everything is different: the UIButton will not dismiss the event, and the UIScrollView will never realize that there was a touch moving over it.
I hope my explanation is accurate and comprensible enough. Let me know if a) it doesn't work or b) there's something unclear.
Good luck :)
Try
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
if (allowAppDrag && [gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
return NO;
}
return YES;
}