如何确定平移手势的真实结束速度?

问题描述 投票:4回答:1

当使用UIPanGestureRecognizer并检测UIGestureRecognizerStateEnded时,手势的速度不是真正的速度。相反,它是我之前调用我的动作方法的旧速度。如何在手势结束时访问真实的速度?

我像这样创建我的UIPanGestureRecognizer

    UIPanGestureRecognizer* panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureRecognized:)];
    [panGestureRecognizer setMaximumNumberOfTouches:2];
    [panGestureRecognizer setMinimumNumberOfTouches:1];
    [panGestureRecognizer setDelegate:self];
    [panGestureRecognizer setDelaysTouchesBegan:NO];
    [panGestureRecognizer setDelaysTouchesEnded:NO];
    [panGestureRecognizer setCancelsTouchesInView:NO];
    [self addGestureRecognizer:panGestureRecognizer];

我的动作方法的开头是:

- (IBAction) panGestureRecognized:(UIPanGestureRecognizer *)recognizer {

    UIGestureRecognizerState state = recognizer.state;

    CGPoint gestureTranslation = [recognizer translationInView:self];
    CGPoint gestureVelocity = [recognizer velocityInView:self];

    [CBAppDelegate log:@"panGestureRecognized: state: %s\n    translation: (%f, %f)\n    velocity: (%f, %f)", [self toString:state], gestureTranslation.x, gestureTranslation.y, gestureVelocity.x, gestureVelocity.y];

日志输出示例:

2013-09-30_10:46:32.830 panGestureRecognized: state: UIGestureRecognizerStateChanged
    translation: (-283.000000, 2.000000)
    velocity: (-43.046783, 45.551472)
2013-09-30_10:47:02.942 panGestureRecognized: state: UIGestureRecognizerStateEnded
    translation: (-283.000000, 2.000000)
    velocity: (-43.046783, 45.551472)

正如你所看到的,两个日志条目中的速度是相同的(相同的翻译故事,但我只关心速度),虽然我在不移动它的情况下按住我的手指约30秒,然后抬起手指。您可以从条目的时间戳中分辨出时间。在不移动我的手指30秒后肯定不会报告速度。

我用iOS 6.1的iOS模拟器测试了这个。

iphone ios uipangesturerecognizer
1个回答
17
投票

仅在发生平移时才定义velocityInView方法。也就是说,只有当您实际移动手指时才会发生平移手势。如果你保持手指不动,它实际上不会触发平移手势。

这意味着没有内置方法来了解手势结束时的移动速度。您可以执行以下操作:检查最后一个事件与状态值之间的时差为UIGestureRecognizerStateChangedUIGestureRecognizerStateEnded。然后,您可以调整此阈值以获得所需的行为。

例如

- (IBAction) panGestureRecognized:(UIPanGestureRecognizer *)recognizer {

    UIGestureRecognizerState state = recognizer.state;

    CGPoint gestureTranslation = [recognizer translationInView:self];
    CGPoint gestureVelocity = [recognizer velocityInView:self];

    if ( state == UIGestureRecognizerStateChanged )
         _lastChange = CFAbsoluteTimeGetCurrent();
    else if ( state == UIGestureRecognizerStateEnded ) {
         double curTime = CFAbsoluteTimeGetCurrent(); 
         double timeElapsed = curTime - _lastChange;
         if ( timeElapsed < MY_THRESHOLD )
              finalSpeed = gestureVelocity;
         else
              finalSpeed = CGPointZero;
    }   
 }

1
投票

2019 how-to ...

这是在手指出现时真正了解速度的唯一方法:

有一些变数......

var cat: CADisplayLink? = nil
var prevTime = CFAbsoluteTimeGetCurrent()
var lastKnownPosition: CGFloat = 0
var lastKnownActualVelocity: Double = 0

然后 ...

@objc func _checkVelocityEveryTrueFrame() {
    let newTime = CFAbsoluteTimeGetCurrent()
    let frameTime = newTime - prevTime
    prevTime = newTime

    let newPos = yourConstraint.constant
    lastKnownActualVelocity = Double(newPos - lastKnownPosition) / frameTime
    lastKnownPosition = newPos
    print("- \(frameTime) \(lastKnownPosition) \(lastKnownActualVelocity)")
}

@objc func dragOrFlick(_ p: UIPanGestureRecognizer) {
    if p.state == .began {
        cat?.invalidate()
        cat = nil
        cat = CADisplayLink(target: self,
             selector: #selector(_checkVelocityEveryTrueFrame))
        cat?.add(to: .main, forMode: .common)
    }

    if p.state == .changed {
        ... p.translation(in: ...
        yourConstraint.constant = new position...
    }

    if p.state == .ended {
        cat?.invalidate()
        cat = nil
        let trueFinalVelocity = lastKnownActualVelocity
        print("trueFinalVelocity is truly \(trueFinalVelocity)")
    }
}

而已。据我所知,没有更简单的方法。

+脚注。任何游戏程序员都会告诉你,即使这有点粗制滥造;它给出了一帧上的柏拉图速度:纯粹主义者会在可讨论的帧数上略微平滑它:/这是一个棘手的问题。

© www.soinside.com 2019 - 2024. All rights reserved.