Update: Though I'd still like to solve this, I ended up switching to animateWithDuration:delay:options:animations:completion:
and it works much nicer. It's missing that nice "bounce" at the end that the spring affords, but at least it's controllable.
I am trying to create a nice gesture-driven UI for iOS but am running into some difficulties getting the values to result in a nice natural feeling app.
I am using animateWithDuration:delay:usingSpringWithDamping:initialSpringVelocity:options:animations:completion:
because I like the bouncy spring animation. I am initializing the velocity
argument with the velocity as given by the gesture recognizer in the completed state. The problem is if I pan quickly enough and let go, the velocity is in the thousands, and my view ends up flying right off the screen and then bouncing back and forth with such dizzying vengeance.
I'm even adjusting the duration of the animation relative to the amount of distance the view needs to move, so that if there are only a few pixels needed, the animation will take less time. That, however, didn't solve the issue. It still ends up going nuts.
What I want to happen is the view should start out at whatever velocity the user is dragging it at, but it should quickly decelerate when reaching the target point and only bounce a little bit at the end (as it does if the velocity is something reasonable).
I wonder if I am using this method or the values correctly. Here is some code to show what I'm doing. Any help would be appreciated!
- (void)handlePanGesture:(UIPanGestureRecognizer*)gesture {
CGPoint offset = [gesture translationInView:self.view];
CGPoint velocity = [gesture velocityInView:self.view];
NSLog(@"pan gesture state: %d, offset: %f velocity: %f", gesture.state, offset.x, velocity.x);
static CGFloat initialX = 0;
switch ( gesture.state ) {
case UIGestureRecognizerStateBegan: {
initialX = self.blurView.x;
break; }
case UIGestureRecognizerStateChanged: {
self.blurView.x = initialX + offset.x;
break; }
default:
case UIGestureRecognizerStateCancelled:
case UIGestureRecognizerStateEnded: {
if ( velocity.x > 0 )
[self openMenuWithVelocity:velocity.x];
else
[self closeMenuWithVelocity:velocity.x];
break; }
}
}
- (void)openMenuWithVelocity:(CGFloat)velocity {
if ( velocity < 0 )
velocity = 1.5f;
CGFloat distance = -40 - self.blurView.x;
CGFloat distanceRatio = distance / 260;
NSLog(@"distance: %f ratio: %f", distance, distanceRatio);
[UIView animateWithDuration:(0.9f * distanceRatio) delay:0 usingSpringWithDamping:0.7 initialSpringVelocity:velocity options:UIViewAnimationOptionBeginFromCurrentState animations:^{
self.blurView.x = -40;
} completion:^(BOOL finished) {
self.isMenuOpen = YES;
}];
}