0

I'm working on an app where most of the touch gestures will be pan gestures (but I'm not using a pan gesture recognizer). I'm using UIGestureRecognizerDelegate and using touchesBegan, touchesMoved, touchesEnded, and touchesCancelled. However, there are a couple of spots on the screen where if a pan starts there I want to recognize it as a tap event instead. I can do this by simply recognize the location in touchesBegan. My question is, can I dealloc the touch at that point to prevent the continuation of the pan? If a pan starts from this location in the screen, it's guaranteed not to really be intended as a pan by the user. I hope this makes sense.

EDIT: I've realized the extra overhead of managing a tap even for a point that should be ignored is insignificant, so I think I'll just do that. I'll keep the question here, though, in case there is a way to stop the gesture from continuing to be tracked.

I also need a suggestion for how to handle the following situation.

Suppose the user starts a pan (not in the area just described, but elsewhere where it really is intended to be a pan), and while the pan is proceeding, another pan is started elsewhere on the screen. How do I recognize this situation?

EDIT: I am now testing whether this code will solve this issue:

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
   return YES;
}

Edit: ARC forbids explicit dealloc, so now I revise my question to a more general one of what, if anything, I can do to suppress further action. Or do I just have to deal with it?

Victor Engel
  • 2,037
  • 2
  • 25
  • 46
  • You can suppress further action. Please see question: http://stackoverflow.com/questions/11667329/ios-disable-pan-gesture-when-objects-overlap?rq=1 – bibo bode Dec 18 '12 at 17:26
  • @Fawaz I don't think that applies to my situation. I have a main view that contains un unknown number of subviews that are essentially sprites moving around. The gesture recognizer I'm working with is attached to the main view, not the subviews. The recognizer never needs to be removed, unless I'm missing something. – Victor Engel Dec 18 '12 at 18:20

4 Answers4

1

You want the UIGestureRecognizerDelegate method gestureRecognizer:shouldReceiveTouch:. As for recognizing when a second pan starts while one is already in progress, you could try a state variable that you set when the gesture recognizer starts recognizing touches.

Brendon
  • 882
  • 6
  • 12
  • I just did a trace of touch locations and touch instances, and I'm surprised by the results. Basically, what I did was to add an NSLog printing out the touch instance number, which I increment as it goes through the touches loop, and print out the touch location. There is only ever one instance. When I add new pan while the previous one is in progress, the locations just update for each one as if the motion is going from one to the other. I thought there would be separate touch instances for each touch. – Victor Engel Dec 18 '12 at 18:37
  • Forget that previous comment. There are separate objects. I must have a bug somewhere that's preventing the second one being recognized. I'll work on that bug before returning to this question. – Victor Engel Dec 18 '12 at 18:45
  • Here's what seems to be happening: UI flow goes: 1)User starts touch1, 2) user moves touch1, 3) user starts touch2, 4) user moves touch2, 5) user ends touch 2, 6) user ends touch1 (was probably moving all along). The result is that `touchesEnded` is called for touch1 but not touch2. This is an unexpected result, and I'm not sure how to handle this. There is a touch object with a begin, moved, but no end or cancelled. So my logic to handle the touch is never called. – Victor Engel Dec 18 '12 at 19:29
  • Did you try setting the recognizers maximimumNumberOfTouches to 1? That may eliminate your second-pan-gesture issue. – Brendon Dec 18 '12 at 20:50
  • What if I want more than one touch to be possible? If this were the issue, I would expect a single object with number of touches to be other than one. That is not the case. – Victor Engel Dec 18 '12 at 20:57
  • If you just need two or three touches to be possible at once, you can try using that many gesture recognizers. I wouldn't call it a great solution but it should be easy to do. – Brendon Dec 21 '12 at 18:20
  • The game I'm working on can have up to four players, each possibly using more than one simultaneous touch. It's not very likely, but it's possible that the upper limit of 11 could actually be used. In any case, my problem was that a subview had user interaction enabled. That combined with tracking touches by object instead of coordinates resolved my problem. – Victor Engel Dec 22 '12 at 03:45
0

I'm not sure I fully understand your question, but perhaps this will help:

First: With ARC you should not try to dealloc anything, but you can disable the Gesture. For example, if you've named the gesture panGesture, you could do this:

panGesture.enabled = NO;

Instead of trying to alloc and dealloc, just enable and disable.

Second: You can track the movements of a pan gesture. In your IBAction method you could capture the coordinates of the first touch, then decide whether you want this to motion to count as a pan or a touch based on where the gesture begins.

For more information on Pan Gestures, I'd suggest you look here:

UIGestureRecognizer Tutorial in iOS 5: Pinches, Pans, and More!

and of course, here:

Event Handling Guide for iOS: Gesture Recognizers

Axeva
  • 4,697
  • 6
  • 40
  • 64
  • I don't recall why I didn't go with the pan gesture recognizer, but it had limitations that were too restricting. I guess I failed to point out that I'm using UIGestureRecognizerDelegate and capturing the begin, moved, ended, and cancelled events. – Victor Engel Dec 18 '12 at 18:23
0

no you cannot deallocate it and that wouldnt work anyways


since you use a GestureRecognizer you could cancel that

@interface UIGestureRecognizer (Cancel)
- (void)cancel;
@end

@implementation UIGestureRecognizer (Cancel)
- (void)cancel
{
    self.enabled = NO;
    self.enabled = YES;
}
@end

OR

you gotta cancel the touches ... but up until now there is only private api to do that. your best bet is to set a bool for your class like _isCanceled

reset it to NO in touchesBegan and set it to YES when you want to end the touch handling

OR

you could save the touches you want to cancel in an NSSET you store in your class and ignore those touches

Daij-Djan
  • 49,552
  • 17
  • 113
  • 135
  • Are you suggesting there exists a cancel method I should use (I don't see one in the documentation) or that I create my own in my subclass? – Victor Engel Dec 18 '12 at 18:03
0

Here are the solutions I wound up using.

To recognize a tap, I simply compare the coordinates for a touch object at the touchesBegan to touchesEnded and consider it a tap if the coordinates are the same or moved insignificantly. I ignore touchesMoved since a touch starting and ending in about the same place yet moving around in between is very unlikely to occur in my app.

To recognize a second pan after the first pan has started, I track touch objects. In this scenario, the first and second pan get two different touch objects. I was originally tracking the coordinates and following the daisy chain matching currentLocation with previousLocation, but that didn't work because the second touch behaves differently from the first for some reason. Anyway, tracking the touch objects is straightforward. As far as the code is concerned, it doesn't "know" whether the second touch object occurs simultaneously with the first one or not.

Victor Engel
  • 2,037
  • 2
  • 25
  • 46