#import "RNNInteractivePopAnimator.h" #import "RNNAnimator.h" #import "RNNAnimatedView.h" #import "RNNElementView.h" #import "RNNRootViewController.h" #import "VICMAImageView.h" @interface RNNInteractivePopAnimator() @property (nonatomic) CGRect topFrame; @property (nonatomic) CGFloat percent; @property (nonatomic) UINavigationController* nc; @property (nonatomic) UIView* imageSnapshot; @property (nonatomic) double totalTranslate; @property (nonatomic) id transitionContext; @end @implementation RNNInteractivePopAnimator -(instancetype)initWithTopView:(RNNElementView*)topView andBottomView:(RNNElementView*)bottomView andOriginFrame:(CGRect)originFrame andViewController:(UIViewController*)vc{ RNNInteractivePopAnimator* interactiveController = [[RNNInteractivePopAnimator alloc] init]; [interactiveController setTopView:topView]; [interactiveController setBottomView:bottomView]; [interactiveController setOriginFrame:originFrame]; [interactiveController setVc:vc]; [interactiveController setNc:vc.navigationController]; return interactiveController; } -(void)startInteractiveTransition:(id)transitionContext{ [super startInteractiveTransition:transitionContext]; } -(BOOL)shouldBeginInteractivePop:(CGPoint)velocity { if (velocity.y > 0) { return YES; } return NO; } -(BOOL)shouldCancelInteractivePop:(UIPanGestureRecognizer*)recognizer { return ([recognizer velocityInView:self.imageSnapshot].y < 0 || self.totalTranslate < 0); } -(void)handleGesture:(UIPanGestureRecognizer*)recognizer { CGPoint translation = [recognizer translationInView:self.topView]; if (recognizer.state == UIGestureRecognizerStateBegan) { CGPoint velocity = [recognizer velocityInView:recognizer.view]; self.nc.delegate = self; if ([self shouldBeginInteractivePop:velocity]) { [self.nc popViewControllerAnimated:YES]; } } else if (recognizer.state == UIGestureRecognizerStateChanged) { self.totalTranslate = self.totalTranslate + translation.y; [self animateAlongsideTransition:^void(id context){ self.imageSnapshot.center = CGPointMake(self.imageSnapshot.center.x + translation.x, self.imageSnapshot.center.y + translation.y); } completion:nil]; [recognizer setTranslation:CGPointMake(0, 0) inView:self.imageSnapshot]; if (self.totalTranslate >= 0 && self.totalTranslate <= 400.0) { [self updateInteractiveTransition:self.totalTranslate/400]; } } else if (recognizer.state == UIGestureRecognizerStateEnded) { if([self shouldCancelInteractivePop:recognizer]) { [self cancelInteractiveTransition]; [UIView animateWithDuration:0.5 delay:0 usingSpringWithDamping:0.8 initialSpringVelocity:0.8 options:UIViewAnimationOptionCurveEaseOut animations:^{ self.imageSnapshot.frame = self.topFrame; } completion:^(BOOL finished) { self.nc.delegate = (RNNRootViewController*)self.vc; }]; } else { [UIView animateWithDuration:0.3 delay:0 usingSpringWithDamping:0.8 initialSpringVelocity:0.8 options:UIViewAnimationOptionCurveEaseOut animations:^{ self.imageSnapshot.frame = self.originFrame; self.imageSnapshot.contentMode = UIViewContentModeScaleAspectFill; if ([self.bottomView resizeMode]) { self.imageSnapshot.contentMode = [RNNAnimatedView contentModefromString:[self.bottomView resizeMode]]; } } completion:^(BOOL finished) { self.nc.delegate = nil; }]; [self finishInteractiveTransition]; } } } - (BOOL)animateAlongsideTransition:(void (^)(id context))animation completion:(void (^)(id context))completion;{ animation(nil); return YES; } - (void)animationEnded:(BOOL)transitionCompleted { } - (NSTimeInterval)transitionDuration:(id )transitionContext { return 0.7; } - (void)animateTransition:(id)transitionContext { self.totalTranslate = 0; self.transitionContext = transitionContext; UIViewController* toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIViewController* fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIView* componentView = [transitionContext containerView]; toVC.view.frame = fromVC.view.frame; UIView* topViewContent = [self.topView subviews][0]; UIImage* image = [[self.topView subviews][0] image]; UIView* imageSnapshot = [[VICMAImageView alloc] initWithImage:image]; CGPoint fromSharedViewFrameOrigin = [topViewContent.superview convertPoint:topViewContent.frame.origin toView:fromVC.view]; CGRect fromOriginRect = CGRectMake(fromSharedViewFrameOrigin.x, fromSharedViewFrameOrigin.y, topViewContent.frame.size.width, topViewContent.frame.size.height); self.topFrame = fromOriginRect; imageSnapshot.contentMode = UIViewContentModeScaleAspectFill; if ([self.topView resizeMode]) { imageSnapshot.contentMode = [RNNAnimatedView contentModefromString:[self.topView resizeMode]]; } imageSnapshot.frame = fromOriginRect; self.imageSnapshot = imageSnapshot; [self.bottomView setHidden:YES]; UIView* toSnapshot = [toVC.view snapshotViewAfterScreenUpdates:true]; toSnapshot.frame = fromVC.view.frame; [componentView insertSubview:(UIView *)toSnapshot atIndex:1]; [componentView addSubview:self.imageSnapshot]; toSnapshot.alpha = 0.0; [self.topView setHidden:YES]; [UIView animateKeyframesWithDuration:(NSTimeInterval)[self transitionDuration:transitionContext] delay:0 options: UIViewKeyframeAnimationOptionAllowUserInteraction animations:^{ [UIView addKeyframeWithRelativeStartTime:0 relativeDuration:1 animations:^{ fromVC.view.alpha = 0; toSnapshot.alpha = 1; }]; } completion:^(BOOL finished) { [self.bottomView setHidden:NO]; [toSnapshot removeFromSuperview]; [self.imageSnapshot removeFromSuperview]; self.totalTranslate = 0; if (![transitionContext transitionWasCancelled]) { [componentView addSubview: toVC.view]; [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; } if ([transitionContext transitionWasCancelled]) { [self.topView setHidden:NO]; [componentView addSubview: fromVC.view]; [transitionContext completeTransition:NO]; } }]; } - (id)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController*)fromVC toViewController:(UIViewController*)toVC { if (operation == UINavigationControllerOperationPop) { return self; } else { return nil; } return nil; } - (id)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id)animationController { return self; } @end