我的想法是使用UIPanGestureRecognizer,然后根据速度进行测试。这个方法行得通,但是如何根据视图当前位置和平移速度设置UIView移动的正确动画持续时间,以便看起来更加平滑?如果我设置一个固定值,与我的手指滑动速度相比,动画要么开始变慢,要么开始变快。
文档说明:
平移手势的速度,以每秒点数表示。速度分为水平和垂直两个方向。
所以我认为,如果你想让你的视图在屏幕外移动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
。
关于在 UIPanGestureRecognizer
中依赖速度的观察:我不知道你的经验如何,但我发现模拟器生成的速度并不是非常有用的。(在设备上还好,但在模拟器上有问题。)
如果您快速地移动手指并突然停下来,等待一会儿,然后才结束手势(例如,用户开始滑动,意识到这并不是他们想要的,所以他们停下来然后松开手指),velocityInView:
在手指离开屏幕时报告的速度似乎是在我停下来等待之前的快速速度,而在这个例子中正确的速度应该是零(或接近于零)。简而言之,报告的速度是在滑动结束前的速度,而不是滑动结束时的速度。
我最终自己手动计算了速度。(这似乎很愚蠢,但如果我真的想得到滑动的最终速度,我没有看到任何绕过它的方法。)总之,在状态为 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];
}
}
UIView
动画器设置UIViewAnimationOptionBeginFromCurrentState
选项就足以使动画无缝继续进行。
UIGestureRecognizerStateEnded
中,最终翻译和上次翻译是相同的,所以最终速度始终为0。 - an0static
变量将使值在应用程序生命周期内持久存在,甚至在另一个对象中也是如此。在使用它们之前,请仔细考虑。 - DCMaxxx