用减速移动UIView

Way*_*man 5 iphone objective-c touch

我需要在减速时点击并拖动屏幕上的UIView.我已经非常好地编写了用于移动具有触摸的视图的代码,但是需要对象以一定程度的惯性(一旦满足某个加速度阈值)继续移动,减速直到它停止,或者满足屏幕的边界.这不适用于游戏,而是使用一些标准的UIView控件.我正在努力解决的最大问题是加速度.

你写的任何好的算法都可以实现同样的目标吗?

编辑:

我在touchesEnded:方法上使用动画块,但是在一个人放开手指和动画开始之间有一个明显的延迟:

[UIView transitionWithView:self 
                  duration:UI_USER_INTERFACE_IDIOM() == 
                               UIUserInterfaceIdiomPhone ? 0.33f : 0.33f * 2.0f
                   options:UIViewAnimationCurveEaseOut 
                animations:^(void){
                        if (dir == 1)   //  Flicked left
                        {
                            self.center = CGPointMake(self.frame.size.width * 0.5f,
                                                      self.center.y);
                        }
                        else {  //  Flicked right
                            self.center = CGPointMake(
                                self.superview.bounds.size.width - 
                                  (self.frame.size.width * 0.5f), self.center.y);
                        }
                     } 
                completion:^(BOOL finished){
                     // Do nothing
                }];
Run Code Online (Sandbox Code Playgroud)

MHC*_*MHC 6

问题在于用于动画的计时功能.动画应该与用户在第一个中拖动一样快,并快速减速.以下代码显示了实现此行为的一个非常简单的示例.

首先,在我的touchesBegan:withEvent:方法中,我将第一个触摸位置记录到我的点缓冲区.我正在缓冲两个触摸位置以获得视图的运动矢量,并且可以有不同的方式来获取矢量.

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
    ivar_lastPoint[0] = [[touches anyObject] locationInView:self];
    ivar_lastPoint[1] = ivar_lastPoint[0];
    ivar_touchOffset.x = ivar_lastPoint[0].x - self.sprite.position.x;
    ivar_touchOffset.y = ivar_lastPoint[0].y - self.sprite.position.y;
    self.lastTime = [NSDate date];
} 
Run Code Online (Sandbox Code Playgroud)

然后,在touchesMoved:withEvent:方法中,我更新了视图的位置.实际上,我使用CALayer而不是视图,因为我想为其动画使用自定义计时功能.因此,我根据用户更新图层的位置,并且对于给定的间隔,我更新位置缓冲区.

#define kSampleInterval 0.02f

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {

    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    /* First of all, move the object */
    CGPoint currentPoint = [[touches anyObject] locationInView:self];
    CGPoint center = self.sprite.position;
    center.x = currentPoint.x - ivar_touchOffset.x;
    center.y = currentPoint.y - ivar_touchOffset.y;
    self.sprite.position = center;

    /* Sample locations */
    NSDate *currentTime = [NSDate date];
    NSTimeInterval interval = [currentTime timeIntervalSinceDate:self.lastTime];
    if (interval > kSampleInterval) {
        ivar_lastPoint[0] = ivar_lastPoint[1];
        ivar_lastPoint[1] = currentPoint;
        self.lastTime = currentTime;
        self.lastInterval = interval;

    }
    [CATransaction commit];
}
Run Code Online (Sandbox Code Playgroud)

self.sprite是我视图中CALayer对象的引用.我不需要动画来拖动,所以我通过使用CATransaction类对象禁用它.

最后,我计算向量并在touchesEnded:withEvent:方法中应用动画.在这里,我创建了一个自定义的CAMediaTimingFunction,因此它真的是"快速进入,缓出".

#define kDecelerationDuration 1.0f
#define kDamping 5.0f

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
    CGPoint targetPoint;
    NSDate *currentTime = [NSDate date];
    NSTimeInterval interval = self.lastInterval + [currentTime timeIntervalSinceDate:self.lastTime];
    targetPoint.x = self.sprite.position.x + (ivar_lastPoint[1].x - ivar_lastPoint[0].x)/interval*kDecelerationDuration/kDamping;
    targetPoint.y = self.sprite.position.y + (ivar_lastPoint[1].y - ivar_lastPoint[0].y)/interval*kDecelerationDuration/kDamping;
    if (targetPoint.x < 0) {
        targetPoint.x = 0;
    } else if (targetPoint.x > self.bounds.size.width) {
        targetPoint.x = self.bounds.size.width;
    }
    if (targetPoint.y < 0) {
        targetPoint.y = 0;
    } else if (targetPoint.y > self.bounds.size.height) {
        targetPoint.y = self.bounds.size.height;
    }
    CAMediaTimingFunction *timingFunction = [CAMediaTimingFunction functionWithControlPoints:
                                             0.1f : 0.9f :0.2f :1.0f];

    [CATransaction begin];
    [CATransaction setValue:[NSNumber numberWithFloat:kDecelerationDuration] forKey:kCATransactionAnimationDuration];
    [CATransaction setAnimationTimingFunction:timingFunction];

    self.sprite.position = targetPoint; 
    [CATransaction commit];

}
Run Code Online (Sandbox Code Playgroud)

这是一个非常简单的例子.您可能需要更好的矢量获取机制.此外,这只移动一个可视组件(CALayer).您可能需要一个UIView对象来处理来自对象的事件.在这种情况下,您可能希望通过CALayer设置动画,并分别移动实际的UIView对象.可以有多种方法一起处理CALayer动画和UIView重定位.