Move UIView with Slowdown

I need to click and drag a UIView on the screen with a slowdown. I wrote the code very nicely to move my eyes with touch, but I need the object to continue to move with a certain degree of inertia (after reaching a certain acceleration threshold), slowing down to a stop or reaching the border of the screen. This is not for the game, but for using some standard UIView controls. The biggest part I'm fighting is acceleration.

Any good algorithms you wrote to do the same?

Edit:

I use the animation block in the method touchesEnded:, but there is a noticeable delay between the time a person takes his finger away and the animation:

[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
                }];
+5
3

, . , . .

-, 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];
} 

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];
}

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];

}

. , . , (CALayer). , , UIView . CALayer UIView . CALayer UIView .

+6

Core Animation. , UIView - , , UIViewAnimationOptionCurveEaseOut . .

+3

, . , , / .

struct Velocity {
float x;
float y; }

Vector acceleration = your acceleration equation. // can be constant

Vector newVelocity = oldVelocity + acceleration * timeDelta;

Vector newPosition = newVelocity * timeDelta;

Assuming you have a normalized vector for your direction of movement, and you just counteract that direction, you can use float instead of Vector.

You must snap the new position to the border. And you must stop the iteration in the delta time when the speed becomes negative.

0
source

All Articles