Advertise Mobile SDKs Books Events Forum News Social Networking Support Us
Follow @iphonedevsdk on Twitter

Mockup & CodeGen, iPhone & iPad
($9.99)

Make your own iPhone apps
and run them live!
(free)

Manu
($0.99)

Want your application or service advertised on iPhone Dev SDK?

Go Back   iPhone Dev SDK Forum > iPhone SDK Development Forums > iPhone SDK Development

Reply
 
LinkBack Thread Tools Display Modes
Old 07-26-2008, 03:33 AM   #1 (permalink)
New Member
 
Join Date: May 2008
Posts: 38
Default Solution: How to Recognize a Touch and Hold

Since this was such a major obstacle for me, I thought I'd share my solution of how to recognize a touch and hold. No sense in others suffering like I did!

In one of the posts I made on these forums asking for help figuring out how to recognize a touch and hold, someone suggested storing the touch in a variable, starting a timer, and then examining the current touch and comparing it to the initial touch. A sound suggestion, except for the last part. As it turns out, I don't think reviewing the current touch is possible when you're talking about doing so outside of the touch event methods (touchesBegan, touchesMoved, and touchesEnded).

Instead, this is the approach I took - which is now working perfectly.

1) In my header file for the class that this code is running in (a UIViewController in my case), I've declared an NSTimer called "touchTimer" and synthesized it in the corresponding implementation file. That, of course, makes it a variable that is accessible across multiple methods in the implementation file.

2) In the touchesBegan event method add the timer to the run loop or call a method that will do so.

Code:
touchTimer = [NSTimer scheduledTimerWithTimeInterval:delay target:self selector:@selector(touchHasBeenHeld:) userInfo:nil repeats:NO];
3) In the "touchHasBeenHeld" method that is called when the timer fires, do whatever you like to have happen when the touch has been held. However, after that functionality you'll need to invalidate the timer if it's currently valid and re-add the timer to the run loop.

Code:
touchTimer = [NSTimer scheduledTimerWithTimeInterval:delay target:self selector:@selector(touchHasBeenHeld:) userInfo:nil repeats:NO];
if ([touchTimer isValid]) [touchTimer invalidate];
That might seem odd to do... I mean, the code that's running here is in a method that is called when the timer fires (at which point the timer should not be valid). And why re-add it to the run loop? If you don't, you'll find that your application will lock up when you touch and hold and then move. I'm not sure I understand exactly why myself.

4) This one is probably obvious if you've read up to this point. In both the touchesMoved and touchesEnded event methods you'll need to invalidate the timer if it's currently valid. In the touchesMoved method, you'll also need to re-add the timer to the run loop just like you did inside the method that the timer triggers. Again, it doesn't really make sense to me just yet... but it prevents the app from locking up when you touch and move. This is not necessary to do in the touchesEnded event method.

Right now I've got a UILabel that I put text into when the touch starts, when it moves, when it ends, and when it's been held for a set number of seconds. And it works flawlessly!

Hope that helps someone out there

-Toryn
torynfarr is offline   Reply With Quote
Old 07-26-2008, 06:42 AM   #2 (permalink)
New Member
 
Join Date: Jul 2008
Posts: 60
Default

Yes, it will help me soon! Thankyou very much!
jazzmic is offline   Reply With Quote
Old 07-26-2008, 07:41 PM   #3 (permalink)
Some guy
 
MattCairns's Avatar
 
Join Date: Jul 2008
Location: Canada
Posts: 103
Send a message via AIM to MattCairns
Default

Awesome, thanks. This will help me with a app I am creating.
MattCairns is offline   Reply With Quote
Old 07-26-2008, 08:24 PM   #4 (permalink)
Lost in a sea of code
 
BostonMerlin's Avatar
 
Join Date: Apr 2008
Location: Boston
Posts: 399
Default

i believe the 'moveme' sample code by apple shows how to do touch-hold and drag as well. i expect you've already looked at that code and it didnt work for you.

john
__________________
----------------------------------------------------------------------
I love being a dad, flying airplanes and writing code.
----------------------------------------------------------------------
Follow me on Twitter: @BostonMerlin
Feed your brain on Twitter: @iPhoneDev101
----------------------------------------------------------------------
iPhone Apps:
BostonMerlin is offline   Reply With Quote
Old 07-27-2008, 02:21 AM   #5 (permalink)
New Member
 
Join Date: May 2008
Posts: 38
Default

Quote:
Originally Posted by bostonmerlin View Post
i believe the 'moveme' sample code by apple shows how to do touch-hold and drag as well. i expect you've already looked at that code and it didnt work for you.

john
Yeah, that's not the same as the touch and hold that I needed. The "moveme" sample simply alters the location of a UIView (named "PlacardView") to match location of the current touch. It's not actually a "touch and hold", it just looks like it because you're dragging the image across the screen. In reality though, it's just a location change in the touchesMoved event method.

What I needed is almost like a new touch event method other than began, moved, and ended. I needed an event that occurs after the touch has been held for a duration of time.

-Toryn
torynfarr is offline   Reply With Quote
Old 07-27-2008, 03:48 AM   #6 (permalink)
Some guy
 
MattCairns's Avatar
 
Join Date: Jul 2008
Location: Canada
Posts: 103
Send a message via AIM to MattCairns
Default

Hey, would it be possible to see some full sample code of this being implemented? I'm still a little confused on how to get this working. If you could it would be of loads help to me!

Matt
MattCairns is offline   Reply With Quote
Old 07-27-2008, 05:16 PM   #7 (permalink)
New Member
 
Join Date: May 2008
Posts: 38
Default

Sure : )


ViewController.h
Code:
#import <UIKit/UIKit.h>

@interface ViewController : UIViewController {
	
	UILabel *touchStatusLabel;
	NSTimer *touchTimer;

}

@property (nonatomic, retain) UILabel *touchStatusLabel;
@property (nonatomic, retain) NSTimer *touchTimer;

@end
ViewController.m
Code:
#import "ViewController.h"

@interface ViewController (PrivateMethods)
- (void)startTouchTimer:(float)delay;
- (void)touchHeld:(NSTimer*)timer;
@end


@implementation ViewController

@synthesize touchTimer, touchStatusLabel;

- (void)loadView {
	
	UIView *containerView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
	containerView.backgroundColor = [UIColor redColor];
	containerView.clearsContextBeforeDrawing = YES;
	self.view = containerView;
	[containerView release];
	
}

- (void)viewDidLoad {

    // Rotates the view into landscape mode, with the home button on the right.
    CGAffineTransform transform = CGAffineTransformMakeRotation(3.14159/2);
    self.view.transform = transform;
	
    // Repositions and resizes the view.
    CGRect contentRect = CGRectMake(-80, 80, 480, 320);
    self.view.bounds = contentRect;

    // Setup a UILabel in the top left corner.
    CGRect labelFrame = CGRectMake(-80, 105, 100, 25);
    touchStatusLabel = [[UILabel alloc] initWithFrame:labelFrame];
    touchStatusLabel.font = [UIFont systemFontOfSize:16];
    touchStatusLabel.textColor = [UIColor whiteColor];
    touchStatusLabel.textAlignment = UITextAlignmentLeft;
    touchStatusLabel.backgroundColor =  [UIColor colorWithRed:0.0 green:0.0 blue:0.0 alpha:0.0];

    [self.view addSubview: touchStatusLabel];

}

- (void)startTouchTimer:(float)delay {
	
	touchTimer = [NSTimer scheduledTimerWithTimeInterval:delay target:self selector:@selector(touchHeld:) userInfo:nil repeats:NO];
	
}

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	
	touchStatusLabel.text = @"Touch Start";
	[self startTouchTimer:3.00];

}

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
	
	touchStatusLabel.text = @"Touch Moved";
	if ([touchTimer isValid]) [touchTimer invalidate];
	[self startTouchTimer:3.00];
	
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {

	touchStatusLabel.text = @"Touch Ended";
	if ([touchTimer isValid]) [touchTimer invalidate];
	
}

- (void)touchHeld:(NSTimer*)timer {

	touchStatusLabel.text = @"Touch Held";
	if ([touchTimer isValid]) [touchTimer invalidate];
	[self startTouchTimer:3.00];
	
}

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {

	return NO;
	
}

- (void)dealloc {
	
	[touchStatusLabel release];
        [touchTimer release];

	[super dealloc];
	
}

@end
This *should* create a big red UIView rotated landscape style with a UILabel in the top right. As the touch state changes, the UILabel should be updated.... with the added bonus of a custom made touch event "touchHeld" which is a touch state that will occur if you hold your finger on the screen for 3 seconds.

Note: I didn't test to see if this compiles... I just took out the stuff from my app that is related specifically to my app... and copy and pasted the rest in here.

Hope this helps clear it up!

-Toryn

Last edited by torynfarr; 07-27-2008 at 05:32 PM.
torynfarr is offline   Reply With Quote
Old 07-27-2008, 11:33 PM   #8 (permalink)
Some guy
 
MattCairns's Avatar
 
Join Date: Jul 2008
Location: Canada
Posts: 103
Send a message via AIM to MattCairns
Default

Awesome! Thanks, that helped me a whole bunch!

Matt
MattCairns is offline   Reply With Quote
Old 10-07-2008, 12:18 PM   #9 (permalink)
ToM
InsiderApps.com
 
Join Date: Jul 2008
Posts: 101
Default

I couldn't get it to compile in my app. :?
ToM is offline   Reply With Quote
Old 01-06-2009, 01:39 AM   #10 (permalink)
Registered Member
 
Join Date: Dec 2008
Posts: 77
Default

This works unless the code takes time to execute (like an animation), if you touch twice quickly the timer will start a second time before the first one ends.
aceallways is offline   Reply With Quote
Old 04-11-2009, 05:02 AM   #11 (permalink)
Registered Member
 
Join Date: Apr 2009
Posts: 62
Default

Hello! New to the forums...

Thanks everyone for all your past comments and suggestions - I've been reading lots over the last 2 weeks and it has been greatly appreciated.

This touch-timer *seems* like it will be very helpful to me, but being new to Objective-C, I'm stuck.

>>> What part of the code is *linking* the events to a finger touch?

I ask because I want to change that trigger - I need this code to do a couple extra things:

1) Respond by tapping a button, preferably something set up in Interface Builder - not just a blank rectangle on the screen.

2) Display different messages based on how long button is pressed. I think I know how to implement this one, but I cannot begin to figure it out until I have a working button first.

I hope I make sense...

Thank you in advance for your insight. GxA
GRANDxADMIRAL is offline   Reply With Quote
Old 04-13-2009, 08:32 PM   #12 (permalink)
Registered Member
 
Join Date: Apr 2009
Posts: 62
Default Quest for knowledge...

Does anyone have any insight into my problem? Thx.
GRANDxADMIRAL is offline   Reply With Quote
Old 09-18-2009, 01:37 AM   #13 (permalink)
Registered Member
 
Join Date: Sep 2009
Posts: 4
Default

Quote:
However, after that functionality you'll need to invalidate the timer if it's currently valid and re-add the timer to the run loop.

That might seem odd to do... I mean, the code that's running here is in a method that is called when the timer fires (at which point the timer should not be valid). And why re-add it to the run loop? If you don't, you'll find that your application will lock up when you touch and hold and then move. I'm not sure I understand exactly why myself.
The reason is being when an NSTimer is invalidated, it is released from memory. So when you try to invoke isValid. The code is looking at a nil pointer or memory location and tells you "this method is not available" and crash.
What you should do is retain the NSTimer after you create the NSTimer
PHP Code:
touchTimer = [NSTimer scheduledTimerWithTimeInterval:delay target:self selector:@selector(touchHeld:) userInfo:nil repeats:YES];
[
touchTimer retain]; 
Then you don't need to re-add the timer to the loop.

Thank you though for your post. It works like a charm. (with the exception of the repeated timer initialization which as I shown is not necessary)
DjHash

P.S. I wont take credit for this.. I found the solution here.. Re: NSTimer

I hope this helps anyone looking for touches held.
djhash is offline   Reply With Quote
Old 03-13-2010, 08:29 AM   #14 (permalink)
Registered Member
 
Join Date: Mar 2010
Posts: 8
Default

The way I check if touch is held is I declare a UItouch pointer in the header files. When a touch happens, I set the UItouch to the touch that has been passed in.

When touches end, I simply set that to nil.

To find out if the a touch is held down, I check to see if its is valid. It will be valid anytime before the touch is ended

Code:
//in header
UITouch *touch;

//start of touch
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
     
     touch = [touches anyObject];
}

//when touches end
- (BOOL)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event{

     NSArray *touchArray = [touches allObjects];
     int count = [touchArray count];
     for(int i = 0; i < count; i++)
     { 
          if(touchArray[i] == touch)
               touch = nil;
     }
}
__________________
____________________________________________
Fistpump Nation - The music is hitting hard and you're fighting back. Beat up that beat!
Speed Demon - The classic card game Speed, with a modern twist.

Last edited by moonshiner; 03-13-2010 at 11:04 PM.
moonshiner is offline   Reply With Quote
Old 09-22-2010, 07:54 AM   #15 (permalink)
Registered Member
 
Join Date: Jul 2010
Posts: 72
Default problem locating a Label..

torynfarr's explanation helped me how to recognize touch. Thanks to torynfarr.
But i want to recognize that a Label is touched. I tried but no luck. Help me in this regard.

Thanks in advance.
Santosh.
santosh_kumar is offline   Reply With Quote
Old 09-23-2010, 02:45 AM   #16 (permalink)
Registered Member
 
Join Date: Jul 2010
Posts: 72
Default Recognizing Label Touch

Quote:
Originally Posted by santosh_kumar View Post
torynfarr's explanation helped me how to recognize touch. Thanks to torynfarr.
But i want to recognize that a Label is touched. I tried but no luck. Help me in this regard.

Thanks in advance.
Santosh.
I'm able to recognize when a Label is touched with the following links.

UILabel: Using the userInteractionEnabled method on a label - Stack Overflow
Point not in Rect but CGRectContainsPoint says yes - Stack Overflow

cheers...
santosh_kumar is offline   Reply With Quote
Old 09-23-2010, 03:34 AM   #17 (permalink)
Registered Member
 
screwtape's Avatar
 
Join Date: Jul 2010
Location: Nottingham
Posts: 54
Send a message via Skype™ to screwtape
Default What about this?

I'm not clear if these extra gesture recognisers only work for iPad, as I'm only in the process of trying them on an iPhone app, but this ought to simplify things if it does...

UILongPressGestureRecognizer Class Reference
screwtape is offline   Reply With Quote
Old 09-26-2010, 03:40 AM   #18 (permalink)
Registered Member
 
Join Date: Jul 2010
Posts: 3
Default

Quote:
Originally Posted by screwtape View Post
I'm not clear if these extra gesture recognisers only work for iPad, as I'm only in the process of trying them on an iPhone app, but this ought to simplify things if it does...
It's implemented in 3.2 for iPhone OS. However, the OS for iPhone itself jumped from 3.1 to 4.0, so you can't use it if you are supporting 3.1.
carolight is offline   Reply With Quote
Reply

Bookmarks

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



» Advertisements
» Online Users: 239
21 members and 218 guests
ADY, AragornSG, bookesp, BrianSlick, Dani77, Dattee, Dominus, dre, glenn_sayers, HemiMG, JasonR, karlam963, nobre84, Oral B, prchn4christ, Raggou, Rudy, spiderguy84, themathminister, viniciusdamone, vvenkatachallam
Most users ever online was 1,187, 10-11-2011 at 08:09 AM.
» Stats
Members: 158,885
Threads: 89,229
Posts: 380,763
Top Poster: BrianSlick (7,129)
Welcome to our newest member, bookesp
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 02:20 PM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.3.0