基于UIPanGestureRecognizer速度的UIView动画

时间:2011-11-14 12:05:30

标签: ios uiview uigesturerecognizer uiviewanimation uipangesturerecognizer

我希望能够在屏幕上和屏幕外移动子视图,就像在iPhone照片应用程序中构建iPhone中的图像一样,所以如果子视图超出屏幕关闭,当我放开我的照片时手指它必须在屏幕上制作动画,但它也必须支持滑动,因此如果滑动/平移速度足够高,它必须在屏幕上显示动画,即使屏幕可能小于1/2。

我的想法是使用UIPanGestureRecognizer,然后测试速度。这是有效的,但是如何基于视图的当前位置和平移速度为UIView的移动设置正确的动画持续时间,使其看起来平滑?如果我设置一个固定值,与我的手指滑动速度相比,动画开始变慢或变快。

3 个答案:

答案 0 :(得分:54)

文档说

  

平移手势的速度,以每秒点数表示。速度分为水平和垂直分量。

所以我想说,鉴于你想要移动你的观点xPoints(用pt测量)让它离开屏幕,你可以计算出这种运动的持续时间,如下所示:

CGFloat xPoints = 320.0;
CGFloat velocityX = [panRecognizer velocityInView:aView].x;
NSTimeInterval duration = xPoints / velocityX;
CGPoint offScreenCenter = moveView.center;
offScreenCenter.x += xPoints;
[UIView animateWithDuration:duration animations:^{
    moveView.center = offScreenCenter;
}];

您可能希望使用+ (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion来尝试不同的UIViewAnimationOptions

答案 1 :(得分:21)

关于依赖UIPanGestureRecognizer速度的观察:我不知道你的经历,但我发现系统在模拟器上产生的速度并不是非常有用。 (它在设备上没问题,但在模拟器上有问题。)

如果您快速平移并突然停止,等待,然后才结束手势(例如,用户开始滑动,意识到这不是他们想要的,所以他们停下来然后释放他们的手指),速度报告当你的手指被释放时,velocityInView:状态下的UIGestureRecognizerStateEnded似乎是我停下来等待之前的快速速度,而此示例中的正确速度将为零(或接近零)。简而言之,报告的速度是它在平底锅结束之前的速度,而不是平底锅结束时的速度。

我最终自己手动计算速度。 (这似乎很愚蠢,这是必要的,但如果我真的想要获得平底锅的最终速度,我没有看到任何方法。)底线,当状态为UIGestureRecognizerStateChanged时我会跟踪当前和之前的translationInView CGPoint以及时间,然后当我在UIGestureRecognizerStateEnded时使用这些值来计算实际最终速度。它工作得很好。

这是我计算速度的代码。我碰巧没有使用速度来计算动画的速度,而是我用它来确定用户是否要足够平移或快速轻弹以使视图移动超过屏幕的一半,从而触发视图之间的动画,但计算最终速度的概念似乎适用于这个问题。这是代码:

- (void)handlePanGesture:(UIPanGestureRecognizer *)gesture
{
    static CGPoint lastTranslate;   // the last value
    static CGPoint prevTranslate;   // the value before that one
    static NSTimeInterval lastTime;
    static NSTimeInterval prevTime;

    CGPoint translate = [gesture translationInView:self.view];

    if (gesture.state == UIGestureRecognizerStateBegan)
    {
        lastTime = [NSDate timeIntervalSinceReferenceDate];
        lastTranslate = translate;
        prevTime = lastTime;
        prevTranslate = lastTranslate;
    }
    else if (gesture.state == UIGestureRecognizerStateChanged)
    {
        prevTime = lastTime;
        prevTranslate = lastTranslate;
        lastTime = [NSDate timeIntervalSinceReferenceDate];
        lastTranslate = translate;

        [self moveSubviewsBy:translate];
    }
    else if (gesture.state == UIGestureRecognizerStateEnded)
    {
        CGPoint swipeVelocity = CGPointZero;

        NSTimeInterval seconds = [NSDate timeIntervalSinceReferenceDate] - prevTime;
        if (seconds)
        {
            swipeVelocity = CGPointMake((translate.x - prevTranslate.x) / seconds, (translate.y - prevTranslate.y) / seconds);
        }

        float inertiaSeconds = 1.0;  // let's calculate where that flick would take us this far in the future
        CGPoint final = CGPointMake(translate.x + swipeVelocity.x * inertiaSeconds, translate.y + swipeVelocity.y * inertiaSeconds);

        [self animateSubviewsUsing:final];
    }
}

答案 2 :(得分:3)

在大多数情况下,为UIViewAnimationOptionBeginFromCurrentState动画师设置UIView选项足以制作完美无瑕的动画。