Advertise here




Advertise here

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Sign In with Google Sign In with OpenID

Single Tap / Double Tap

torynfarrtorynfarr Posts: 38Registered Users
edited June 2011 in iPhone SDK Development
If I want my application to do something when the screen is single tapped (touch.tapCount == 1) and something different when the screen is double tapped (touch.tapCount == 2), what is the best way of handling this?

I want the actions that the single tap triggers to only occur when the screen is single tapped. I don't want double tapping the screen to do both the single tap action *and* the double tap actions.

Is there a way to do this without using an NSTimer? Right now, I've got an NSTimer that starts in the touchesEnded event method if the tap count is equal to 1. Also in the touchesEnded event method is code that... if the tapCount is greater than 1, invalidates the timer. I have the timer duration set to 0.25 seconds. This works... but I'd like a more elegant solution.

-Toryn
Post edited by torynfarr on

Replies

  • scottiphonescottiphone Posts: 802Registered Users
    edited August 2008
    The iPhone Programming Guide on Apple's site specifically gives snippets to deal with this.
  • torynfarrtorynfarr Posts: 38Registered Users
    edited August 2008
    The iPhone Programming Guide on Apple's site specifically gives snippets to deal with this.

    Where? Where are there "specifically" snippets that deal with this?

    In here?

    iPhone Dev Center

    ... because I couldn't see anything that specifically addressed my question.

    Could you do me a favor and not reply to my threads any more? I don't want to argue with you or start a silly flame war or something. But these one sentence replies are not very helpful or productive. And you don't just do them to me.. you reply to like everyone's question like this.
  • scottiphonescottiphone Posts: 802Registered Users
    edited August 2008
    Page 145 iPhone Programming Guide - This should the first pdf people read after learning Objective-C

    HandlingSingleandMultipleTapGestures
    AverycommongestureiniPhoneapplicationsisthetap:theusertapsanobjectwithhisorherfinger.
    Aresponderobjectcanrespondtoasingletapinoneway,adouble-tapinanother,andpossiblya
    triple-tapinyetanotherway.Todeterminethenumberoftimestheusertappedaresponderobject,
    yougetthevalueofthetapCountpropertyofaUITouchobject.
    ThebestplacestofindthisvaluearethemethodstouchesBegan:withEvent:and
    touchesEnded:withEvent:.Inmanycases,thelattermethodispreferredbecauseitcorrespondsto
    thetouchphaseinwhichtheuserliftsafingerfromatap.Bylookingforthetapcountinthetouch-up
    phase(UITouchPhaseEnded),youensurethatthefingerisreallytappingandnot,forinstance,touching
    downandthendragging.
    144 HandlingMulti-TouchEvents
    2008-07-08 | ©2008AppleInc. AllRightsReserved.

    In Listing 7-1, the touchesEnded:withEvent: method implementation responds to a double-tap
    gesture by zooming in on (or out from) the content shown in a scroll view.
    Listing 7-1 Handling a double-tap gesture
    - (void) touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event
    {
    UIScrollView *scrollView = (UIScrollView*)[self superview];
    UITouch *touch = [touches anyObject];
    CGSize size;
    CGPoint point;
    if([touch tapCount] == 2) {
    if(![_viewController _isZoomed]) {
    point = [touch locationInView:self];
    size = [self bounds].size;
    point.x /= size.width;
    point.y /= size.height;
    [_viewController _setZoomed:YES];
    size = [scrollView contentSize];
    point.x *= size.width;
    point.y *= size.height;
    size = [scrollView bounds].size;
    point.x -= size.width / 2;
    point.y -= size.height / 2;
    [scrollView setContentOffset:point animated:NO];
    }
    else
    [_viewController _setZoomed:NO];
    }
    }
    A complication arises when a responder object wants to handle a single-tap and a double-tap gesture
    in different ways. For example, a single tap might select the object and a double tap might display a
    view for editing the item that was double-tapped. How is the responder object to know that a single
    tap is not the first part of a double tap? Here is how a responder object could handle this situation
    using the event-handling methods just described:
    1. In touchesEnded:withEvent:, when the tap count is one, the responder object sends itself a
    performSelector:withObject:afterDelay: message. The selector identifies another method
    implemented by the responder to handle the single-tap gesture; the object for the second parameter
    is the related UITouch object; the delay is some reasonable interval between a single- and a
    double-tap gesture.
    2. In touchesBegan:withEvent:, if the tap count is two, the responder object cancels the pending
    delayed-perform invocation by sending itself a cancelPreviousPerformRequestsWithTarget:
    message. If the tap count is not two, the method identified by the selector in the previous step
    for single-tap gestures is invoked after the delay.
    3. In touchesEnded:withEvent:, if the tap count is two, the responder performs the actions necessary
    for handling double-tap gestures.
    C H A P T E R 7
    Event Handling
  • craig t mackenziecraig t mackenzie Posts: 53Registered Users
    edited August 2008
    torynfarr wrote: »
    Could you do me a favor and not reply to my threads any more? I don't want to argue with you or start a silly flame war or something. But these one sentence replies are not very helpful or productive. And you don't just do them to me.. you reply to like everyone's question like this.

    With all due respect a lot of questions can easily be answered yourself (and myself, and all of ourselves) by being gently nudged in the right direction.

    Sometimes we don't have enough time to write an essay response to every question asked, but know roughly where the right info is in the (mountains) of professionally written documentation Apple Provides.

    I can understand how frustrating learning new things can be, but to be so rude to another member of the community isn't an option in my opinion.

    Perhaps you could explain more clearly what you're after, so other people can help?
  • StitchStitch Posts: 401Registered Users
    edited August 2008
    torynfarr wrote: »
    Could you do me a favor and not reply to my threads any more? I don't want to argue with you or start a silly flame war or something. But these one sentence replies are not very helpful or productive. And you don't just do them to me.. you reply to like everyone's question like this.

    Are you being serious? That one line reply given to you (with an hour of posting) told you everything you needed apart from the page number.

    The best thing you can do right now, if you haven't already is to download all of the pdf documents available and keep them locally. You'll answer most of your own questions very quickly by just doing a search. They are invaluable.
    <a href="http://itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=311941449&mt=8" target="_blank">BUZZER!</a> : <font color="Sienna">iTunes Library Music Quiz (1 or 2 Player)</font>
  • torynfarrtorynfarr Posts: 38Registered Users
    edited August 2008
    Honestly, one line responses aren't helpful.

    I don't understand what the point of replying to someone's question is when you just shoot out one line responses, telling the person to "look it up in the documentation"

    I already looked at the SDK documentation and the PDF mentioned. There are no snippets of code that specifically address handling separate actions for a single tap and double tap.

    The only thing in that PDF that pertains to my question is:

    "1. In touchesEnded:withEvent:, when the tap count is one, the responder object sends itself a
    performSelector:withObject:afterDelay: message. The selector identifies another method
    implemented by the responder to handle the single-tap gesture; the object for the second parameter
    is the related UITouch object; the delay is some reasonable interval between a single- and a
    double-tap gesture. "

    And that sounds like it still involves using an NSTimer (for the delay portion)?



    I see these one line responses from (only a few people) all the time, and I think it's a detriment to this development community. I'm not expecting long essays or even examples of code for every single question that people ask. But suggestions other than "look it up in the documentation" are a lot more productive than this.

    That being said, yes... sometimes people ask questions that are so general... or so very clear that they haven't attempted to find the answer on their own. Politely pointing them to the documentation makes sense. But given that my question in this case was specific, and that I have it working already using an NSTimer, and I'm just looking for a more elegant solution (one that doesn't involve using a timer)... I think one could infer from that.... that I've read the documentation.

    I'm not the only one here who has gotten frustrated at replies like that. I've seen a lot of other questions posted that are well stated, with examples of the problem, source code, etc. etc. and get very dismissive replies.
  • NosNos Posts: 132Registered Users
    edited August 2008
    I have the same problem.
    I would like my application do something when the screen is single tapped (touch.tapCount == 1) and nothing when the screen is double tapped (touch.tapCount == 2) or more.
    But, the problem is : when the screen is double tapped or more, the app execute the first tap.
    How can I resolve this ?
  • JumeJume Posts: 264Registered Users
    edited August 2008
    Nos wrote: »
    I have the same problem.
    I would like my application do something when the screen is single tapped (touch.tapCount == 1) and nothing when the screen is double tapped (touch.tapCount == 2) or more.
    But, the problem is : when the screen is double tapped or more, the app execute the first tap.
    How can I resolve this ?

    first check for double (or triple or more) taps and exit if true.. else you have a single tap.
  • NosNos Posts: 132Registered Users
    edited August 2008
    It doesn't work. It always executes the first tap action even if you tap a second or more time.
  • rhuettlrhuettl Posts: 246Registered Users
    edited September 2008
    Hi guys,

    i think you are missunderstanding the initial question. He is not asking how double tap (with two fingers and maybe on different points) is working - there are many examples showing this.

    He (and me too) likes to know how a double tap (like a mouse double klick) can be handled - means: two tips on THE SAME point/position in a specified delta of time (0.25 seconds or below) occured.

    I think you have to measure the delta between the first touch end and the second one. If the point on these two touches are the same (+/- a delta of some pixels) and the time delta is < 250msec then you are in a double tap.

    But you have to solve one problem. If you handle a one tap and a double tap you should suspense the one tap until >= 250msec so that you know that there no douple tap will occur.

    Any implementation examples out?

    Cheers
    Ralf
  • rhuettlrhuettl Posts: 246Registered Users
    edited September 2008
    Ah, by the way:
    Where is the performselector:withobject:afterDelay function? If i look at the docs i cant find one with the afterDeley parameters...

    :-) Ralf
  • PhoneyDeveloperPhoneyDeveloper Posts: 1,431Registered Users
    edited September 2008
    Where is the performselector:withobject:afterDelay function? If i look at the docs i cant find one with the afterDeley parameters...

    Are you really saying that you don't know how to use the Find window?

    Open the multifile find window. Type into the find box: performSelector. Select 'Find in Frameworks'. Click the Find button. You will see numerous results. A few of them will also include afterDelay.

    Open the header file that has the result you want in it. Option-double-click on the performSelector text in the header file and the appropriate doc will open.

    If you didn't know this stuff you need to read the Xcode documentation. You will never be productive if you can't find functions in the header files and in the docs from their names.

    BTW, to the OP, your code doesn't need to deal with timers if it uses performselector:withobject:afterDelay
  • rnievesrnieves Posts: 50Registered Users
    edited June 2009
    That stuff in the programming guide actually does work, it sounds great but I want to be able to send the event and the touch to the singleTap method since this will forward it if necessary to another responder. I cannot do this with this solution.


    I have tried using a timer but there seems to be a problem. Can anybody tell me what might be wrong.

    In my touchesBegan method I did
    	if ([doubleTapTimer isValid]) {
    		[doubleTapTimer invalidate];
    		doubleTapTimer = nil;
    	}
    	if(![doubleTapTimer isValid]) {
    		[self startTouchTimer:DOUBLE_TAP_TIMER withTouch:touches andEvent:event];
    	} else if (tapCount == 2) {
    		if(self.zoomedView) {
    			[self resetScrollZoom];
    		} else {
    			[super touchesBegan:touches withEvent:event];
    		}
    		[doubleTapTimer invalidate];
    		doubleTapTimer = nil;
    		return;
    	}
    

    Then in my startTouchTimer method I prepare my timer with an invocation to call the singleTapMethod.
    //Prepare invocation
    	SEL singleTapSelector = @selector(singleTapDone:withEvent:);  //selector
    	NSMethodSignature * sig = [[self class] instanceMethodSignatureForSelector:singleTapSelector]; //signature to initialize
    	NSInvocation *singleTapObjects = [NSInvocation invocationWithMethodSignature:sig]; //initialize selector
    	[singleTapObjects setTarget:self];
    	[singleTapObjects setSelector:singleTapSelector];
    	[singleTapObjects setArgument:&touches atIndex:2];		//set parameters for invocations
    	[singleTapObjects setArgument:&event atIndex:3];
    	
    	
    	doubleTapTimer = [NSTimer scheduledTimerWithTimeInterval:delay invocation:singleTapObjects repeats:NO];
    
    

    This successfully calls the singleTapMethod and when looking at the debugger the objects passed are the same (location wise) but when calling [super touchesBegan:withEvent] on this method it does not handle it at all. Nothing happens. If I just implement the [super touchesBegan:withEvent] on the touchesBegan method it successfully handles it by forwarding it.

    BTW already tried using self.nextResponder to try and force it myself to forward the touchesBegan but it won't work either.


    Edit:

    I did some more research and although the touch and event do get forwarded, when getting to the touchesBegan on the subview they have been forwarded to the reason they don't work is because getting the coordinates and/or the tapCount returns cero for the touch. Can anybody please shed some light on this situations?
  • jarsonjarson Posts: 26Registered Users
    edited September 2009
    This code works great for me ( I go up to triple taps here):
    -(void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
    {
    	NSUInteger numTaps = [[touches anyObject] tapCount];
    	if (numTaps < 2) {
    		[self performSelector:@selector(doThis) withObject:nil afterDelay: 0.5 ];
    		
    		[self.nextResponder touchesEnded:touches withEvent:event];
    	} else {
    		if(numTaps == 2) {
    			[NSObject cancelPreviousPerformRequestsWithTarget:self];
    
    			[self performSelector:@selector(doSomethingElse) withObject:nil afterDelay: 0.5 ];
    		}		
    
    		if(numTaps == 3){
    			//				NSLog(@"3 taps - Previous");
    
    			[NSObject cancelPreviousPerformRequestsWithTarget:self];
    
    			[self doSomethingElseCompletely];
    			
    		}
    	}
    	
    }
    

    Only thing is I wish I could increase the tap-area, but I'll start a new topic for that.
  • artaxerxesartaxerxes Posts: 7New Users
    edited June 2011
    Thanks all - this thread was just the inspiration i needed to overcome the issue I had with single and double taps triggering at the same instance.
  • dany_devdany_dev Posts: 4,696Tutorial Authors, Registered Users @ @ @ @ @
    edited June 2011
  • thh022thh022 Posts: 77Registered Users
    edited June 2011
    To handle one tap...

    h-file:
    UITapGestureRecognizer *tapGestureRecognizer;
    
    @property(nonatomic, retain) UITapGestureRecognizer *tapGestureRecognizer;
    

    m-file:
    @synthesize tapGestureRecognizer;
    
    // VIEWDIDLOAD
    UITapGestureRecognizer *newTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTaps:)];
    self.tapGestureRecognizer = newTapGestureRecognizer;
    self.tapGestureRecognizer.numberOfTouchesRequired = 1;
    self.tapGestureRecognizer.numberOfTapsRequired = 1;
    [self.view addGestureRecognizer:self.tapGestureRecognizer];
    [newTapGestureRecognizer release];
    
    // FUNCTION CALLED WHEN SCREEN IS TAPPED ONCE
    -(void)handleTaps:(UITapGestureRecognizer*)paramSender{
    }
    
Sign In or Register to comment.