// // UIViewController+TFPresent.m // trueface // // Created by Apple on 2019/10/12. // Copyright © 2019 jie. All rights reserved. // #import "UIViewController+TFPresent.h" #import "AppDelegate.h" @interface TFPresentAnimation:NSObject @property(nonatomic,assign,getter=isPresentation)BOOL presentation; @property(nonatomic,assign)TFDirection direction; -(NSTimeInterval)transitionDuration:(id)transitionContext; -(void)animateTransition:(id)transitionContext; @end @implementation TFPresentAnimation +(instancetype)presentAnimationWithDirection:(TFDirection)direction isPresentation:(BOOL)isPresentation { TFPresentAnimation * presentAnimation = [[TFPresentAnimation alloc] init]; presentAnimation.direction = direction; presentAnimation.presentation = isPresentation; return presentAnimation; } -(NSTimeInterval)transitionDuration:(id)transitionContext; { return 0.25f; } -(void)animateTransition:(id)transitionContext { //1 UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; //2 CGRect backRect = transitionContext.containerView.bounds; if (self.presentation && toVC.view) { UIView * backView = [[UIView alloc] initWithFrame:backRect]; backView.backgroundColor = [UIColor blackColor]; backView.alpha = 0.5; UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc] initWithTarget:fromVC action:@selector(TFDismissViewController)]; [backView addGestureRecognizer:tap]; [[transitionContext containerView] addSubview:backView]; [[transitionContext containerView] addSubview:toVC.view]; } CGSize finalSize = self.presentation? toVC.preferredContentSize:fromVC.preferredContentSize; CGFloat final_X=0,final_Y=0; switch (self.direction) { case TFDirectionCenter: { final_X = (CGRectGetWidth(backRect)-finalSize.width)/2.0; final_Y = (CGRectGetHeight(backRect)-finalSize.height)/2.0; } break; case TFDirectionTop: { final_X = (CGRectGetWidth(backRect)-finalSize.width)/2.0; final_Y = 0; } break; case TFDirectionLeft: { final_X = 0; final_Y = (CGRectGetHeight(backRect)-finalSize.height)/2.0; } break; case TFDirectionRight: { final_X = (CGRectGetWidth(backRect)-finalSize.width); final_Y = (CGRectGetHeight(backRect)-finalSize.height)/2.0; } break; case TFDirectionBottom: { final_X = (CGRectGetWidth(backRect)-finalSize.width)/2.0; final_Y = (CGRectGetHeight(backRect)-finalSize.height); } break; default: break; } CGRect finalRect = CGRectMake(final_X, final_Y, finalSize.width, finalSize.height); UIView * animationView = self.presentation?toVC.view:fromVC.view; NSInteger count = transitionContext.containerView.subviews.count; UIView *alphaView = transitionContext.containerView.subviews[count-2]; alphaView.alpha = self.presentation?0:0.4f; //3 switch (self.direction) { case TFDirectionCenter: { animationView.frame = self.presentation?CGRectOffset(finalRect, 0,[UIScreen mainScreen].bounds.size.height-final_Y):finalRect; } break; case TFDirectionTop: { animationView.frame = self.presentation?CGRectOffset(finalRect, 0,finalSize.height*(-1)):finalRect; } break; case TFDirectionLeft: { animationView.frame = self.presentation?CGRectOffset(finalRect, finalSize.width*(-1),0):finalRect; } break; case TFDirectionRight: { animationView.frame = self.presentation?CGRectOffset(finalRect, finalSize.width,0):finalRect; } break; case TFDirectionBottom: { animationView.frame = self.presentation?CGRectOffset(finalRect, 0, finalSize.height):finalRect; } break; default: break; } [UIView animateWithDuration:[self transitionDuration:transitionContext] delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{ switch (self.direction) { case TFDirectionCenter: { animationView.frame = self.presentation?finalRect:CGRectOffset(finalRect, 0,[UIScreen mainScreen].bounds.size.height-final_Y); } break; case TFDirectionTop: { animationView.frame = self.presentation?finalRect:CGRectOffset(finalRect, 0,finalSize.height*(-1)); } break; case TFDirectionLeft: { animationView.frame = self.presentation?finalRect:CGRectOffset(finalRect, finalSize.width*(-1),0); } break; case TFDirectionRight: { animationView.frame = self.presentation?finalRect:CGRectOffset(finalRect, finalSize.width,0); } break; case TFDirectionBottom: { animationView.frame = self.presentation?finalRect:CGRectOffset(finalRect, 0, finalSize.height); } break; default: break; } alphaView.alpha = self.presentation?0.4f:0; } completion:^(BOOL finished) { [transitionContext completeTransition:YES]; }]; } @end @interface TFTransitionDelegate : NSObject @property (nonatomic,assign)TFDirection direction; -(id)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source; @end @implementation TFTransitionDelegate +(instancetype)transtionDelegateWithDirection:(TFDirection)direction { TFTransitionDelegate * delegate = [[TFTransitionDelegate alloc] init]; delegate.direction = direction; return delegate; } -(nullable id)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source; { return [TFPresentAnimation presentAnimationWithDirection:self.direction isPresentation:YES]; } -(nullable id)animationControllerForDismissedController:(UIViewController *)dismissed { return [TFPresentAnimation presentAnimationWithDirection:self.direction isPresentation:NO]; } @end @implementation UIViewController (TFPresent) - (BOOL)TF_unAllowTouched { NSNumber *number = objc_getAssociatedObject(self, &unAllowTouched); return [number boolValue]; } -(void)TF_setunAllowTouched:(BOOL)disAllowTouch { NSNumber *number = [NSNumber numberWithBool: disAllowTouch]; objc_setAssociatedObject(self, &unAllowTouched, number, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } -(void)TFPresentVC:(UIViewController *)viewControllerToPresent completion:(PresentCompletion)completion { [kAppDelegate.window.rootViewController TF_setunAllowTouched:NO]; viewControllerToPresent.modalPresentationStyle = UIModalPresentationCustom; viewControllerToPresent.preferredContentSize = CGSizeMake(KScreenWidth, KScreenHeight); TFTransitionDelegate * transitionDelegate = [TFTransitionDelegate transtionDelegateWithDirection:TFDirectionCenter]; viewControllerToPresent.transitioningDelegate = transitionDelegate; [[LCTools getNilPresentationController:self] presentViewController:viewControllerToPresent animated:YES completion:completion]; } -(void)TFPresentViewController:(UIViewController *)viewControllerToPresent presentSize:(CGSize)presentSize direction:(TFDirection)direction completion:(PresentCompletion)completion { [kAppDelegate.window.rootViewController TF_setunAllowTouched:NO]; viewControllerToPresent.modalPresentationStyle = UIModalPresentationCustom; viewControllerToPresent.preferredContentSize = presentSize; TFTransitionDelegate * transitionDelegate = [TFTransitionDelegate transtionDelegateWithDirection:direction]; viewControllerToPresent.transitioningDelegate = transitionDelegate; // [self presentViewController:viewControllerToPresent animated:YES completion:completion]; [[LCTools getNilPresentationController:self] presentViewController:viewControllerToPresent animated:YES completion:completion]; } //add by leo 不能点击返回 -(void)TFPresentViewControllerUnTouched:(UIViewController *)viewControllerToPresent presentSize:(CGSize)presentSize direction:(TFDirection)direction completion:(PresentCompletion)completion { //并没有起作用 跳转前和跳转后self不同 add by leo 20191226 // tf_swizzled_method(self.class, @"TFDismissViewController", self.class); [kAppDelegate.window.rootViewController TF_setunAllowTouched:YES]; viewControllerToPresent.modalPresentationStyle = UIModalPresentationCustom; viewControllerToPresent.preferredContentSize = presentSize; TFTransitionDelegate * transitionDelegate = [TFTransitionDelegate transtionDelegateWithDirection:direction]; viewControllerToPresent.transitioningDelegate = transitionDelegate; [[LCTools getNilPresentationController:self] presentViewController:viewControllerToPresent animated:YES completion:completion]; // //防止二次弹出时位置偏移 // [kAppDelegate.window.rootViewController presentViewController:viewControllerToPresent animated:YES completion:completion]; } -(void)TFDismissViewController { BOOL unalloTouched= [self TF_unAllowTouched]; if(!unalloTouched) [self dismissViewControllerAnimated:YES completion:nil]; } -(void)UnTouched_TFDismissViewController { // [self UnTouched_TFDismissViewController]; //[self dismissViewControllerAnimated:YES completion:nil]; } static inline void tf_swizzled_method(Class oldClass ,NSString *oldSelector, Class newClass) { NSString *newSelector = [NSString stringWithFormat:@"UnTouched_%@", oldSelector]; SEL originalSelector = NSSelectorFromString(oldSelector); SEL swizzledSelector = NSSelectorFromString(newSelector); Method originalMethod = class_getInstanceMethod(oldClass, NSSelectorFromString(oldSelector)); Method swizzledMethod = class_getInstanceMethod(newClass, NSSelectorFromString(newSelector)); BOOL isAdd = class_addMethod(oldClass, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); if (isAdd) { class_replaceMethod(newClass, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); }else { method_exchangeImplementations(originalMethod, swizzledMethod); } } @end