filtering single and double taps - iphone

When the user single taps my view, i need one specific method to run.
When the user double taps, i need another method do take place.
The problem is that the double tap triggers the single tap, and it introduce bugs in my logic.
I can't use UIGestureRecognizer because i need to keep track of the points.
I try some booleans, but no chance. I also tried the cancel/perfomSelector-delay technique, but it does not work (that's strange because other folks on other forums said it works, maybe the simulator touch detection is different ?)
I'm trying to let the user set the position (drag, rotate) of a board piece, but i need to be aware of piece intersections, clip to the board area, etc, that's why a simple boolean will not solve the problem.
Thanks in advance!

Check this, seems right what you are looking for:
Below the code to use UITapGestureRecognizer to handle single tap and double tap. The code is designed that it won't fire single tap event if we got double tap event. The trick is use requireGestureRecognizerToFail to ask the single tap gesture wait for double tap event failed before it fire. So when the user tap on the screen, the single tap gesture recognizer will not fire the event until the double tap gesture recognizer. If the double tap gesture recognizer recognize the event, it will fire a double tab event and skip the single tap event, otherwise it will fire a single tap event.
UITapGestureRecognizer *doubleTapGestureRecognizer = [[UITapGestureRecognizer alloc]
initWithTarget:self action:#selector(handleDoubleTap:)];
doubleTapGestureRecognizer.numberOfTapsRequired = 2;
//tapGestureRecognizer.delegate = self;
[self addGestureRecognizer:doubleTapGestureRecognizer];
//
UITapGestureRecognizer *singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(handleSingleTap:)];
singleTapGestureRecognizer.numberOfTapsRequired = 1;
[singleTapGestureRecognizer requireGestureRecognizerToFail: doubleTapGestureRecognizer];
//tapGestureRecognizer.delegate = self;
[self addGestureRecognizer:singleTapGestureRecognizer];
Possibly I don't understand exactly what you mean by "i need to keep track of the points", but I don't see any problems with doing this with a gesture recognizer.

Swift 3 Solution:
doubleTap = UITapGestureRecognizer(target: self, action:#selector(self.doubleTapAction(_:)))
doubleTap.numberOfTapsRequired = 2
singleTap = UITapGestureRecognizer(target: self, action:#selector(self.singleTapAction(_:)))
singleTap.numberOfTapsRequired = 1
singleTap.require(toFail: doubleTap)
self.view.addGestureRecognizer(doubletap)
self.view.addGestureRecognizer(singleTap)
In the code line singleTap.require(toFail: doubleTap) we are forcing the single tap to wait and ensure that the tap even is not a double tap. Which means we are asking to ensure the double tap event has failed hence it is concluded as a single tap.

Swift Solution :
doubleTapSmall1.numberOfTapsRequired = 2
doubleTapSmall1.addTarget(self, action: "doubleTapPic1")
smallProfilePic1.addGestureRecognizer(doubleTapSmall1)
singleTapSmall1.numberOfTapsRequired = 1
singleTapSmall1.addTarget(self, action: "singleTapPic1")
singleTapSmall1.requireGestureRecognizerToFail(doubleTapSmall1)
smallProfilePic1.addGestureRecognizer(singleTapSmall1)

Just implement the UIGestureRecognizer delegate methods by setting the delegate properly.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch{
return YES;
}
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer{
return YES;
}
Also add this line of code
[singleTap requireGestureRecognizerToFail:doubleTap];

Related

Tap Gesture + Long Press Gesture both not working Together

I want use tap gesture and long press gesture together in a view. But my problem is that I can't able to run tap gesture action on tap. But Long press gesture is working fine.
Here is code snippet.
UILongPressGestureRecognizer *longPressGesture=[[UILongPressGestureRecognizer alloc]initWithTarget:self action:#selector(ontappLongPressGesture:)];
longPressGesture.minimumPressDuration=0.6;
longPressGesture.delegate=self;
[cell.view addGestureRecognizer:longPressGesture];
UITapGestureRecognizer *gesture=[[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(cellSelected:)];
//[gesture requireGestureRecognizerToFail:longPressGesture]; //I have tried with this line also but not working
gesture.delegate=self;
[cell.view addGestureRecognizer:gesture];
Also I have set delegate method also
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
return YES;
}
This method is getting called on long press
- (void)ontappLongPressGesture:(id)sender{
//Long press code here
}
But this method is not getting called on tap
-(void)cellSelected:(id)sender {
//Single tap code here
}
You haven't specified what type of view your putting these gestureRecognizer's on, however since you are calling it "cell", I'm assuming its on a UITableView?
You need to make sure you set the cancelsTouchesInView flag if so:
gesture.cancelsTouchesInView=NO;
You either need to use one of these two ways.
- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldReceiveTouch:(UITouch *)touch {
// test if our control subview is on-screen
if (cell.view.superview != nil) {
if ([touch.view isDescendantOfView:cell.view]) {
// we touched our control surface
return YES; // handle the touch
}
}
return NO; // ignore the touch
}
Here you need to specify the view for which you want the gestureRecognizer.
Or you can also use these lines of code
gesture.cancelsTouchesInView = NO;
longPressGesture.cancelsTouchesInView = NO;
Hope it will help you.

Stopping a UIGestureRecognizer from calling selector

I'm adding in a few UIGestureRecognizers with a target and selector. I'll just talk about one since the other will be the same i'm sure.
I've added a UIPinchGestureRecognizer
UIPinchGestureRecognizer *pinch = [UIPinchGestureRecognizer new];
[pinch addTarget:self action:#selector(pinchGestureDetected:)];
[self.view setMultipleTouchEnabled:YES];
[self.view addGestureRecognizer:pinch];
Now my goal here is to simply call this method once when I receive a pinch gesture. But obvoiusly it continues to call it as the person pinches. I'm using it as part of a page navigation and will be updating the view when a pinch in is detected.
So in my -(void)pinchGestureDetected:(UIPinchGestureRecognizer)pinch method I'll be calling another method. Kinda like ... and this is a little sudo
-(void)pinchGestureDetected:(UIPinchGestureRecognizer)pinch
{
if (pinch.scale > 1) layoutViewWithMoreDetail;
else layoutViewWithLessDetail;
}
So I don't want it to keep calling this method or the layout method will continue to be called. I want one layout / pinch gesture.
Is there a way I can stop detecting the pinch once it has determined the scale?? Something along the way of ...
-(void)pinchGestureDetected:(UIPinchGestureRecognizer)pinch
{
if (pinch.scale > 1)
{
layoutViewWithMoreDetail;
stop receiving pinch gestures till this.gesture is finished;
}
Would I impliment the GestureDelegate??
-(void)pinchGestureDetected:(UIPinchGestureRecognizer)pinch
{
if (pinch.scale > 1 && pinching == NO )
{
layoutViewWithMoreDetail;
pinching = YES;
}
and then in the delegate for Gesture ended ... pinching = NO;
Thanks for any help
UPinchGestureRecognizer is a continuous gesture - use if(pinch.state == UIGestureRecognizerStateBegan) to detect whether or not the event is just now starting.
However, this results in a low threshold for triggering the event. An alternate method is to quicky disable and enable a gesture when it has been triggered to your satisfaction, like so:
-(void)pinchGestureDetected:(UIPinchGestureRecognizer)pinch
{
if (pinch.scale > 1)
{
//do your stuff here
pinch.enabled = NO;
pinch.enabled = YES;
}
}
This is because if you look at the documentation, it states:
enabled
A Boolean property that indicates whether the gesture recognizer is enabled.
#property(nonatomic, getter=isEnabled) BOOL enabled
Discussion
Disables a gesture recognizers so it does not receive touches. The default value is YES. If you change this property to NO while a gesture recognizer is currently recognizing a gesture, the gesture recognizer transitions to a cancelled state.

UILongPressGestureRecognizer on UITableViewCell does not work in iOS 5 and 4.3

I have a table view, and I use UILongPressGestureRecognizer on table view cell to show a context menu over the cell to allow user perform some extra functionality. Everything is work well in iOS 5.1, but when I test in iOS 5 and 4.3, the event is not fired.
Does anyone know how to solve this problem please help me, thanks in advance.
Below is my code:
in tableViewCell.h: add UIGestureRecognizerDelegate
in tableViewCell.m
UILongPressGestureRecognizer *longPressRecognizer = [[UILongPressGestureRecognizer alloc]
initWithTarget:self action:#selector(handleLongPress:)];
longPressRecognizer.minimumPressDuration = 1.5;
longPressRecognizer.numberOfTouchesRequired = 1;
longPressRecognizer.numberOfTapsRequired = 0;
longPressRecognizer.delegate = self;
[self addGestureRecognizer:longPressRecognizer];
[longPressRecognizer release];
// Method to handle event
- (void)handleLongPress:(UILongPressGestureRecognizer *)gestureRecognizer
{
if (gestureRecognizer.state == UIGestureRecognizerStateBegan)
{
// Do something.
}
}
After spending 1.5 days on this issue, I discover that somehow the tableView receives long press event but tableViewCell does not on iOS 5/4.3 . So I fixed this issue by adding UILongPressGuestureRecognizer to tableView then in the long press event handler then call tableViewCell to show the context menu, and it works.
I met this problem too. I found that long press gesture recognizer works fine only when 'delegate' property is 'NULL'. So just try to remove this line.
longPressRecognizer.delegate = self;

detecting long tap on iPhone

I am working on an iPhone app which requires me to check if the button has been tapped & held pressed for 6 seconds & then fire an action which is playing some sort of sound.
How should I detect this 6 second tap?
On the other hand the user can also keep on tapping button for 6 seconds & then the same action should fire.
What should I do with multiple taps, how would I know that all the taps fall under the 6 second bracket?
For a six second long press, use a UILongPressGestureRecognizer with its minimumPressDuration property set to 6.
Write your own gesture recognizer (say, LongTappingGestureRecognizer) for continuous tapping for a given period; it shouldn't be too tricky. Give it a property like UILongPressGestureRecognizer's minimumPressDuration (say, minimumTappingDuration) and a property (say, maximumLiftTime) that determines how long a finger can be lifted off before it's not considered to be a long tapping gesture.
When it first receives touchesBegan:withEvent:, record the time.
When it receives touchesEnded:withEvent:, start an NSTimer (the lift timer) that sends the gesture recognizer a cancel message (e.g. cancelRecognition) after maximumLiftTime.
When it receives touchesBegan:withEvent: when there's a start time, cancel the lift timer (if any).
The cancelRecognition will transition to the failed state.
There are various strategies for handling recognizing when the end of the gesture is reached, after minimumTappingDuration. One is to check in both the touchesBegan:withEvent: and touchesEnded:withEvent: handlers if the difference between the current time and the start time is >= minimumTappingDuration. The problem with this is that it will take longer than minimumTappingDuration to recognize the gesture if the user is tapping slowly and hir finger is down when the minimumTappingDuration is reached. Another approach is to start another NSTimer (the recognition timer) when the first touchesBegan:withEvent: is received, one that will cause transition to the recognized state and that is cancelled in cancelRecognition. The tricky thing here is what to do if the finger is lifted when the timer fires. The best approach might be a combination of the two, ignoring the recognition timer if the finger is lifted.
There's more to the details, but that's the gist. Basically, it's a long press recognizer that lets the user lift hir finger off the screen for brief periods. You could potentially use just the tapping recognizer and skip the long press recognizer.
I realize this is quite dated question, however answer should be pretty simple.
In your View controller viewDidLoad:
//create long press gesture recognizer(gestureHandler will be triggered after gesture is detected)
UILongPressGestureRecognizer* longPressGesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:#selector(gestureHandler:)];
//adjust time interval(floating value CFTimeInterval in seconds)
[longPressGesture setMinimumPressDuration:6.0];
//add gesture to view you want to listen for it(note that if you want whole view to "listen" for gestures you should add gesture to self.view instead)
[self.m_pTable addGestureRecognizer:longPressGesture];
[longPressGesture release];
Then in your gestureHandler:
-(void)gestureHandler:(UISwipeGestureRecognizer *)gesture
{
if(UIGestureRecognizerStateBegan == gesture.state)
{//your code here
/*uncomment this to get which exact row was long pressed
CGPoint location = [gesture locationInView:self.m_pTable];
NSIndexPath *swipedIndexPath = [self.m_pTable indexPathForRowAtPoint:location];*/
}
}
Here is my solution.
- (IBAction) micButtonTouchedDownAction {
self.micButtonTimer = [NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:#selector(micButtonAction:) userInfo:nil repeats:YES];
self.micButtonReleased = FALSE;
}
- (IBAction) micButtonTouchedUpInsideAction {
self.micButtonReleased = TRUE;
}
- (IBAction) micButtonTouchedUpOutsideAction {
self.micButtonReleased = TRUE;
}
- (void) micButtonAction:(NSTimer *)timer {
[self.micButtonTimer invalidate];
self.micButtonTimer = nil;
if(self.micButtonReleased) {
NSLog(#"Tapped");
}
else {
NSLog(#"Touched");
}
}

How to Recognize a Hold Button {iPhone SDK}

Hi i have a Button i want hold this button to write something but i don't know how can i recognize hold button , can you help me ? thank you
TouchDownInside event triggered, start a NStimer.
TouchUpInside event triggered, cancel the timer.
Make the timer call your method to execute if the user holds the button : the timer delay will be the amount of time required to recognize hold.
You can also use UILongPressGestureRecognizer.
In your initialization method (e.g. viewDidLoad), create a gesture recognizer and attach it to your button:
UILongPressGestureRecognizer *gesture = [[UILongPressGestureRecognizer alloc]
initWithTarget:self
action:#selector(myButtonLongPressed:)];
// you can control how many seconds before the gesture is recognized
gesture.minimumPressDuration = 2;
// attach the gesture to your button
[myButton addGestureRecognizer:gesture];
[gesture release];
The event handler myButtonLongPressed: should look like this:
- (void) myButtonLongPressed:(UILongPressGestureRecognizer *)gesture
{
// Button was long pressed, do something
}
Note that UILongPressGestureRecognizer is a continuous event recognizer.
While the user is still holding down the button, myButtonLongPressed: will be called multiple times.
If you just want to handle the first call, you can check the state in myButtonLongPressed::
if (gesture.state == UIGestureRecognizerStateBegan) {
// Button was long pressed, do something
}