iOS:如何获取长按手势的持续时间?

20

我正在制作一个游戏,其中一个游戏对象的属性通过长按该对象来设置。该属性的值由长按手势的持续时间决定。为此,我正在使用UILongPressGestureRecognizer,代码类似于:

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

然后是处理函数。

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

在这种情况下,我如何获取长按手势的持续时间?

7个回答

30

我相信手势不会存储这些信息以供您访问。您只能在手势上设置一个名为minimumPressDuration的属性,表示手势被识别前的时间。

使用iOS 5的解决方法(未经测试):

创建一个名为timer的NSTimer属性:@property (nonatomic, strong) NSTimer *timer;

和一个计数器:@property (nonatomic, strong) int counter;

然后进行@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];
    }
}

因此,当手势开始时,请启动一个计时器,每秒触发递增方法,直到手势结束。在这种情况下,您将希望将 minimumPressDuration 设置为 0,否则手势不会立即启动。然后可以随意处理计数器!


请检查上面的代码,希望它能适用于您!如果您没有使用iOS 5,则可能需要进行一些更改。 - Rupert Horlick
1
我一直在避免为此目的创建一个属性,但我想没有其他办法了。我使用NSDate而不是NSTimer,这样代码会更清晰。感谢你的回答! - Ryan Dao

9

不需要计时器。您可以通过以下方式实现:

- (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;
    }
}

同时,在创建手势识别器时,不要忘记将手势识别器的minimumPressDuration设置为0,如果你想获得长按的真实持续时间:
myLongPressGestureRecognizer.minimumPressDuration = 0


6

在面向对象的Cocoa Touch中,最干净、最简单的解决方案似乎是子类化UILongPressGesture。以下是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")
            }
    }

如果您想包括从第一次点击开始的时间,可以在计算持续时间时添加手势.minimumPressDuration。缺点是它可能不是微秒精确的,因为触发手势和.Start处理程序被调用之间可能会有少量时间流逝。但对于绝大多数应用程序来说,这并不重要。

4

请查看“minimumPressDuration”属性。根据文档:

手指必须在视图上按下的最短时间,才能识别此手势。

[...]

时间间隔以秒为单位。默认持续时间为0.5秒。


问题是关于持续时间的,即用户按住手指的时间有多长,minimumPressDuration用于设置手势触发前的延迟。 - SafeFastExpressive
对于那些不想硬编码“神奇数字”的人,请使用以下内容获取默认值:[UILongPressGestureRecognizer new].minimumPressDuration - Albert Renshaw

1

您可以在Swift 3.0中通过以下方式获得它

逻辑:只需分配按下的时间并在触摸结束时找到时间差

代码:

//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
}

1
我知道这是一个晚回答,但在IOS 7和8中,这对我非常完美地运行,而无需创建计时器。
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

0

似乎在新的iOS版本中(目前为10),长按识别器用于.begin.ended两个状态的回调会在事件结束后同时发生,即只有当您从屏幕上抬起手指时才会发生。

这使得两个事件之间的差异只有几毫秒,而不是您实际寻找的内容。

在此问题得到解决之前,我决定从头开始用Swift创建另一个手势识别器,并且这将是它的工作原理。

import UIKit.UIGestureRecognizerSubclass
class LongPressDurationGestureRecognizer : UIGestureRecognizer {
        private var startTime : Date?
        private var _duration = 0.0
        public var duration : Double {
            get {
                return _duration
            }
        }
        override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
            startTime = Date() // now
            state = .begin
            //state = .possible, if you would like the recongnizer not to fire any callback until it has ended
        }
        override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
            _duration = Date().timeIntervalSince(self.startTime!)
            print("duration was \(duration) seconds")
            state = .ended
            //state = .recognized, if you would like the recongnizer not to fire any callback until it has ended
        }
 }

然后,您可以轻松访问LongPressDurationGestureRecognizer手势识别器的.duration属性。

例如:

func handleLongPressDuration(_ sender: LongPressDurationGestureRecognizer) {
        print(sender.duration)
}

这个具体的例子并没有考虑到实际发生了多少次触摸或它们的位置。但是你可以轻松地通过扩展LongPressDurationGestureRecognizer来进行调整。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接