#import #import "RNNAnimator.h" #import "RNNElementView.h" #import "RNNInteractivePopAnimator.h" #import "VICMAImageView.h" #import "RNNTransitionStateHolder.h" #import "RNNElementFinder.h" #import "RNNViewLocation.h" #import "RNNAnimatedView.h" @interface RNNAnimator() @property (nonatomic, strong)NSArray* animations; @property (nonatomic)double duration; @property (nonatomic)double springDamping; @property (nonatomic)double springVelocity; @property (nonatomic, strong) RNNInteractivePopAnimator* interactivePopAnimator; @property (nonatomic) BOOL backButton; @property (nonatomic, strong) UIViewController* fromVC; @property (nonatomic, strong) UIViewController* toVC; @end @implementation RNNAnimator - (instancetype)initWithAnimationsDictionary:(NSDictionary *)animationsDic { self = [super init]; if (animationsDic) { [self setupTransition:animationsDic]; } else { return nil; } return self; } -(void)setupTransition:(NSDictionary*)data{ if ([data objectForKey:@"animations"]) { self.animations= [data objectForKey:@"animations"]; } else { [[NSException exceptionWithName:NSInvalidArgumentException reason:@"No animations" userInfo:nil] raise]; } if ([data objectForKey:@"duration"]) { self.duration = [[data objectForKey:@"duration"] doubleValue]; } else { self.duration = 0.7; } if ([data objectForKey:@"springDamping"]) { self.springDamping = [[data objectForKey:@"springDamping"] doubleValue]; } else { self.springDamping = 0.85; } if ([data objectForKey:@"springVelocity"]) { self.springVelocity= [[data objectForKey:@"springVelocity"] doubleValue]; } else { self.springVelocity = 0.8; } self.backButton = false; } -(NSArray*)prepareSharedElementTransition:(NSArray*)RNNSharedElementsToVC andfromVCElements:(NSArray*)RNNSharedElementsFromVC withComponentView:(UIView*)componentView { NSMutableArray* transitions = [NSMutableArray new]; for (NSDictionary* transition in self.animations) { RNNTransitionStateHolder* transitionStateHolder = [[RNNTransitionStateHolder alloc] initWithTransition:transition]; RNNElementFinder* elementFinder = [[RNNElementFinder alloc] initWithToVC:self.toVC andfromVC:self.fromVC]; [elementFinder findElementsInTransition:transitionStateHolder]; RNNViewLocation* animatedViewLocations = [[RNNViewLocation alloc] initWithTransition:transitionStateHolder andVC:self.fromVC]; RNNAnimatedView* animatedView = [[RNNAnimatedView alloc] initWithTransition:transitionStateHolder andLocation:animatedViewLocations andIsBackButton:self.backButton]; transitionStateHolder.locations = animatedViewLocations; [componentView addSubview:animatedView]; [componentView bringSubviewToFront:animatedView]; transitionStateHolder.animatedView = animatedView; [transitions addObject:transitionStateHolder]; if (transitionStateHolder.isSharedElementTransition){ [transitionStateHolder.toElement setHidden: YES]; } [transitionStateHolder.fromElement setHidden:YES]; } return transitions; } -(void)animateTransitions:(NSArray*)transitions { for (RNNTransitionStateHolder* transition in transitions ) { [UIView animateWithDuration:transition.duration delay:transition.startDelay usingSpringWithDamping:transition.springDamping initialSpringVelocity:transition.springVelocity options:UIViewAnimationOptionCurveEaseOut animations:^{ RNNAnimatedView* animatedView = transition.animatedView; if (!self.backButton) { [self setAnimatedViewFinalProperties:animatedView toElement:transition.toElement fromElement:transition.fromElement isSharedElementTransition:transition.isSharedElementTransition withTransform:transition.locations.transform withCenter:transition.locations.toCenter andAlpha:transition.endAlpha]; } else { [self setAnimatedViewFinalProperties:animatedView toElement:transition.fromElement fromElement:transition.fromElement isSharedElementTransition:transition.isSharedElementTransition withTransform:transition.locations.transformBack withCenter:transition.locations.fromCenter andAlpha:transition.startAlpha]; } } completion:^(BOOL finished) { }]; } } -(void)setAnimatedViewFinalProperties:(RNNAnimatedView*)animatedView toElement:(RNNElementView*)toElement fromElement:(RNNElementView*)fromElement isSharedElementTransition:(BOOL)isShared withTransform:(CGAffineTransform)transform withCenter:(CGPoint)center andAlpha:(double)alpha { animatedView.alpha = alpha; animatedView.center = center; animatedView.transform = transform; if (isShared) { if ([[fromElement subviews][0] isKindOfClass:[UIImageView class]]) { animatedView.contentMode = UIViewContentModeScaleAspectFill; if ([toElement resizeMode]){ animatedView.contentMode = [RNNAnimatedView contentModefromString:[toElement resizeMode]]; } } } } -(void)animateComplition:(NSArray*)transitions fromVCSnapshot:(UIView*)fromSnapshot andTransitioningContext:(id)transitionContext { [UIView animateWithDuration:[self transitionDuration:transitionContext ] delay:0 usingSpringWithDamping:self.springDamping initialSpringVelocity:self.springVelocity options:UIViewAnimationOptionCurveEaseOut animations:^{ self.toVC.view.alpha = 1; } completion:^(BOOL finished) { for (RNNTransitionStateHolder* transition in transitions ) { [transition.fromElement setHidden:NO]; if (transition.isSharedElementTransition) { [transition.toElement setHidden:NO]; } RNNAnimatedView* animtedView = transition.animatedView; [animtedView removeFromSuperview]; if (transition.interactivePop) { self.interactivePopAnimator = [[RNNInteractivePopAnimator alloc] initWithTopView:transition.toElement andBottomView:transition.fromElement andOriginFrame:transition.locations.fromFrame andViewController:self.toVC]; UIPanGestureRecognizer* gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self.interactivePopAnimator action:@selector(handleGesture:)]; [transition.toElement addGestureRecognizer:gesture]; } } [fromSnapshot removeFromSuperview]; if (![transitionContext transitionWasCancelled]) { self.toVC.view.alpha = 1; [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; self.backButton = true; } }]; } - (NSTimeInterval)transitionDuration:(id )transitionContext { return self.duration; } - (void)animateTransition:(id)transitionContext { UIViewController* toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; UIViewController* fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIView* componentView = [transitionContext containerView]; self.fromVC = fromVC; self.toVC = toVC; toVC.view.frame = fromVC.view.frame; UIView* fromSnapshot = [fromVC.view snapshotViewAfterScreenUpdates:true]; fromSnapshot.frame = fromVC.view.frame; [componentView addSubview:fromSnapshot]; [componentView addSubview:toVC.view]; toVC.view.alpha = 0; NSArray* onlyForTesting = @[]; NSArray* onlyForTesting2 = @[]; NSArray* transitions = [self prepareSharedElementTransition:onlyForTesting andfromVCElements:onlyForTesting2 withComponentView:componentView]; [self animateComplition:transitions fromVCSnapshot:fromSnapshot andTransitioningContext:transitionContext]; [self animateTransitions:transitions]; } @end