Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS: How to get duration of long press gesture?

I'm working on a game in which an attribute of a game object is set by long pressing on the object itself. The value of the attribute is determined by the duration of the long press gesture. I'm using UILongPressGestureRecognizer for this purpose, so it's something like this:

[gameObjectView addGestureRecognizer:[[UILongPressGestureRecognizer alloc] 
                                       initWithTarget:self action:@selector(handle:)]];

Then the handler function

- (void)handle:(UILongPressGestureRecognizer)gesture {
  if (gesture.state == UIGestureRecognizerStateEnded) {
    // Get the duration of the gesture and calculate the value for the attribute
  }
}

How do I get the duration of the long press gesture in this case?

like image 668
Ryan Dao Avatar asked Feb 23 '12 18:02

Ryan Dao


6 Answers

I'm pretty sure the gesture doesn't store this information for you to access. You can only set a property on it called minimumPressDuration that is the amount of time before the gesture is recognised.

Workaround with ios 5 (untested):

Create an NSTimer property called timer: @property (nonatomic, strong) NSTimer *timer;

And a counter: @property (nonatomic, strong) int counter;

Then @synthesize

- (void)incrementCounter {
    self.counter++;
}

- (void)handle:(UILongPressGestureRecognizer)gesture {
    if (gesture.state == UIGestureRecognizerStateBegan) {
         self.counter = 0;
         self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(incrementCounter) userInfo:nil repeats:yes];
    }
    if (gesture.state == UIGestureRecognizerStateEnded) {
        [self.timer invalidate];
    }
}

So when the gesture begins start a timer that fires the incrementation method every second until the gesture ends. In this case you'll want to set the minimumPressDuration to 0 otherwise the gesture won't start straight away. Then do whatever you want with counter!

like image 137
Rupert Horlick Avatar answered Nov 18 '22 17:11

Rupert Horlick


No timers needed. You can achieve it this way:

- (void)handleRecognizer:(UILongPressGestureRecognizer *)gesture
{
    static NSTimeInterval pressStartTime = 0.0; //This can be moved out and kept as a property
    
    switch ([gesture state])
    {
        case UIGestureRecognizerStateBegan:
            //Keeping start time...
            pressStartTime = [NSDate timeIntervalSinceReferenceDate];
            break; /* edit*/
        case UIGestureRecognizerStateEnded:
        {
            //Calculating duration
            NSTimeInterval duration = [NSDate timeIntervalSinceReferenceDate] - pressStartTime;
            //Note that NSTimeInterval is a double value...
            NSLog(@"Duration : %f",duration);
            break;
        }
        default:
            break;
    }
}

Also, don't forget to set the gesture recognizer's minimumPressDuration to 0 while creating it, if you want to get the real duration of the long press:
myLongPressGestureRecognizer.minimumPressDuration = 0

like image 30
Just Shadow Avatar answered Nov 18 '22 18:11

Just Shadow


It seems by far the cleanest and simplest solution in object oriented Cocoa Touch is to subclass UILongPressGesture. Here is an example written in Swift.

    class MyLongPressGesture : UILongPressGestureRecognizer {
        var startTime : NSDate?
    }

    func installGestureHandler() {
            let longPress = MyLongPressGesture(target: self, action: "longPress:")
            button.addGestureRecognizer(longPress)
    }

    @IBAction func longPress(gesture: MyLongPressGesture) {
            if gesture.state == .Began {
                    gesture.startTime = NSDate()
            }
            else if gesture.state == .Ended {
                    let duration = NSDate().timeIntervalSinceDate(gesture.startTime!)
                    println("duration was \(duration) seconds")
            }
    }

If you want to include the time from first tap, you can include it when you calculate duration, by adding back gesture.minimumPressDuration. The drawback is that it is probably not be micro-second precise, given there is likely a small (tiny) amount of time elapsing between the gesture being triggered and your .Start handler being called. But for the vast majority of applications that shouldn't matter.

like image 24
SafeFastExpressive Avatar answered Nov 18 '22 18:11

SafeFastExpressive


See the "minimumPressDuration" property. According to the documentation:

The minimum period fingers must press on the view for the gesture to be recognized.

[...]

The time interval is in seconds. The default duration is is 0.5 seconds.

like image 36
fbernardo Avatar answered Nov 18 '22 16:11

fbernardo


I know this is a late answer but this works perfectly for me in IOS 7 & 8 without having to create a timer.

UILongPressGestureRecognizer *longGR = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(yourAction)]; // create the recognizer
longGR.minimumPressDuration = 10.0f; //Ten Seconds
longGR.allowableMovement = 50.0f; //Allowable Movement while being pressed
[gameObjectView setUserInteractionEnabled:YES]; //If setting interaction to a non-interactable object such as a UIImageView
[gameObjectView addGestureRecognizer:longGR]; //Add the gesture recognizer to your object
like image 1
inVINCEable Avatar answered Nov 18 '22 18:11

inVINCEable


You can get it by Following in Swift 3.0

Logic : Just assigning the time of press and find the difference of time when touch ends

Code :

//variable to calculate the press time
static var pressStartTime: TimeInterval = 0.0

func handleRecognizer(gesture: UILongPressGestureRecognizer) -> Double {
    var duration: TimeInterval = 0

    switch (gesture.state) {
    case .began:
        //Keeping start time...
        Browser.pressStartTime = NSDate.timeIntervalSinceReferenceDate

    case .ended:
        //Calculating duration
        duration = NSDate.timeIntervalSinceReferenceDate - Browser.pressStartTime
        //Note that NSTimeInterval is a double value...
        print("Duration : \(duration)")

    default:
        break;
    }

    return duration
}
like image 1
Janmenjaya Avatar answered Nov 18 '22 17:11

Janmenjaya