41

我希望能够在屏幕上移动子视图和在屏幕上移动子视图,就像您在 iPhone 内置的照片应用程序中浏览图像一样,所以如果子视图在我用手指放开时超过屏幕 1/2,它必须离屏动画,但它还必须支持滑动,所以如果滑动/平移速度足够高,它必须在离屏动画,即使它可能小于屏幕外的 1/2。

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

4

3 回答 3

59

文档说

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

所以我想说,如果你想移动你的视图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.

于 2011-11-15T18:01:47.860 回答
22

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

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

我最终自己手动计算了速度。(这似乎很愚蠢,但如果我真的想获得平底锅的最终速度,我没有看到任何解决方法。)底线,当状态是UIGestureRecognizerStateChanged我跟踪当前和以前的translationInViewCGPoint 为以及时间,然后使用这些值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];
    }
}
于 2012-05-02T16:33:05.683 回答
3

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

于 2014-08-31T16:25:40.030 回答