Question

I want to use a swipe animation for a custom view that is on top of the view of my UIViewController. The user should be able to swipe up the custom view to the top to send it out of the screen. Exactly like the iOS7 App Switcher gesture to kill an app:

enter image description here

At the moment I use a UIPanGestureRecognizer, that is attached to my custom view. When the custom view's is dragged in the upper 100 pixels of the parent view, I start an UIAnimation to send the custom view out of the parent view:

- (IBAction)panWasRecognized:(UIPanGestureRecognizer *)recognizer
{
    if (recognizer.state == UIGestureRecognizerStateEnded && _myView.center.y >= 100)
    {
        [self resetViewPosition];
    }
    else
    {
        CGPoint translation = [recognizer translationInView:_myView.superview];

        CGPoint center = _myView.center;
        center.x += translation.x;
        center.y += translation.y;
        _myView.center = center;

        if (center.y < 100)
        {
            NSLog(@"swipe up gesture detected ...");
            [self hideView];
        }

        [recognizer setTranslation:CGPointZero inView:_myView.superview];
    }
}

This method is working, but not quite as well as the iOS7 app switcher. Is there a better way to do this?

EDIT:

So here is what works for me:

- (IBAction)panWasRecognized:(UIPanGestureRecognizer *)recognizer
{
    CGPoint velocity = [recognizer velocityInView:recognizer.view];

    if (recognizer.state == UIGestureRecognizerStateEnded && _myView.center.y >= 150)
    {
        [self resetViewPosition];
    }
    else
    {
        CGPoint translation = [recognizer translationInView:_myView.superview];

        CGPoint center = _myView.center;
        center.x += translation.x;
        center.y += translation.y;
        _myView.center = center;

        if (recognizer.state == UIGestureRecognizerStateEnded && center.y < 150)
        {
            NSLog(@"swipe up gesture detected ...");

            // speed
            CGFloat xPoints = -170.0f;
            CGFloat velocityX = [recognizer velocityInView:self.view].x;
            NSTimeInterval duration = xPoints / velocityX;

            [self hideViewWithDuration:duration];
        }
    }

    [recognizer setTranslation:CGPointZero inView:_myView.superview];
}

- (void)hideViewWithDuration:(float)duration
{
    NSLog(@"Animation duration: %f", duration);

    [UIView animateWithDuration:duration
                          delay:0.0f
                        options: UIViewAnimationOptionCurveEaseOut
                     animations:^
     {
         CGRect frame = _myView.frame;
         frame.origin.y = -170;
         frame.origin.x = 10;
         _myView.frame = frame;
     }
                     completion:^(BOOL finished)
     {
         [_myView setHidden:YES];
         CGRect frame = _myView.frame;
         frame.origin.y = self.view.frame.size.height;
         frame.origin.x = 10;
         _myView.frame = frame;
         [_myView setHidden:NO];
         NSLog(@"View is hidden.");
         _hideInProgress = NO;
     }];
}

- (void)resetViewPosition
{       
    [UIView animateWithDuration:0.5
                          delay:0
                        options: UIViewAnimationOptionCurveEaseOut
                     animations:^
     {
         CGRect frame = _myView.frame;
         frame.origin.y = (self.view.frame.size.height - _myView.frame.size.height) / 2;
         frame.origin.x = 10;
         _myView.frame = frame;
     }
                     completion:^(BOOL finished)
     {
         NSLog(@"View is back to its original place.");
     }];
}
Was it helpful?

Solution

There are several parts here.

  1. Point of release. It can be "over the line", when view will be removed or "under", when it will return to the starting position.
  2. Speed during the release. If the speed is high, then "view does have enough energy to go over the line".

So, if the point is "high enough" or the speed is "high enough", we will remove the view, or will return it back otherwise.

Third thing is removal/returning animation. It does need to have inertia to behave more physically correct. You can make simple thing. Let the duration to the "remove window" animation depend on 1/speed. So faster you go, faster the animation will be.

Return animation is a little bit trickier. Window has to go a little bit up and then down. It's where UIKit Dynamics can come handy.

I did all the things except "return animation" for my project and it looks very nice.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top