iOS开发自定义转场动画
1、转场动画
iOS7之后开发者可以自定义界面切换的转场动画,就是在模态弹出(present、dismiss),Navigation的(push、pop),TabBar的系统切换效果之外自定义切换动画!
模态弹出自定义出push、pop效果,可以侧滑:
2、实现步骤
2.1、自定义转场动画
1》创建自定义文件
@interface CustomTransform : NSObject<UIViewControllerAnimatedTransitioning>
2》实现UIViewControllerAnimatedTransitioning方法
//设置转场时间 - (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext; //设置转场效果 - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;
.m相关类说明:
//表示转场动画上下文 UIViewControllerContextTransitioning //当前控制器fromVC和目标控制器toVC //vc1-->present-->vc2: fromVC是vc1,toVC是vc2 //vc2-->dismiss-->vc1: fromVC是vc2,toVC是vc1 UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; //对应控制器的view视图 UIView *fromView =[transitionContext viewForKey:UITransitionContextFromViewKey]; UIView *toView =[transitionContext viewForKey:UITransitionContextToViewKey]; //presentingViewController,presentedViewController vc1-->present-->vc2,vc1.presentedViewController 就是vc2;vc2.presentingViewController 就是vc1。 //更新动画进度 - (void)updateInteractiveTransition:(CGFloat)percentComplete; //转场结束 - (void)finishInteractiveTransition; //转场取消 - (void)cancelInteractiveTransition;
自定义文件:
#import <Foundation/Foundation.h> #import <UIKit/UIKit.h> typedef NS_ENUM(NSInteger, PresentType){ PresentTypePresent, PresentTypeDismiss }; @interface CustomTransform : NSObject<UIViewControllerAnimatedTransitioning> + (instancetype)makeWithTransitionType:(PresentType)type; - (instancetype)initWithTransitionType:(PresentType)type; @end
#import "CustomTransform.h" @interface CustomTransform() @property(nonatomic, assign)PresentType type; @property(nonatomic, strong)UIView *containerView; @end @implementation CustomTransform + (instancetype)makeWithTransitionType:(PresentType)type { return [[self alloc] initWithTransitionType:type]; } - (instancetype)initWithTransitionType:(PresentType)type { if (self == [super init]) { _type = type; } return self; } - (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext { return .5; } - (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext { switch (_type) { case PresentTypePresent: [self presentTransform:transitionContext]; break; case PresentTypeDismiss: [self dismissTransform:transitionContext]; break; default: break; } } - (void)presentTransform:(id<UIViewControllerContextTransitioning>)transitionContext { UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; self.containerView = [transitionContext containerView]; UIView *fromView =[transitionContext viewForKey:UITransitionContextFromViewKey]; UIView *toView =[transitionContext viewForKey:UITransitionContextToViewKey]; [self.containerView addSubview:toView]; CGRect visibleFrame = [transitionContext initialFrameForViewController:fromVC]; CGRect rightHiddenFrame = CGRectMake( CGRectGetWidth(visibleFrame), 0,CGRectGetWidth(visibleFrame),CGRectGetHeight(visibleFrame)); CGRect leftHiddenFrame =CGRectMake(- CGRectGetWidth(visibleFrame), 0, CGRectGetWidth(visibleFrame), CGRectGetHeight(visibleFrame)); fromView.frame = visibleFrame; toView.frame = rightHiddenFrame; fromView.layer.masksToBounds = toView.layer.masksToBounds = YES; [self.containerView insertSubview:toView atIndex:0]; [UIView animateWithDuration:.5 animations:^{ fromView.frame = leftHiddenFrame; toView.frame = visibleFrame; } completion:^(BOOL finished) { if ([transitionContext transitionWasCancelled]) { [toView removeFromSuperview]; } [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; }]; } - (void)dismissTransform:(id<UIViewControllerContextTransitioning>)transitionContext { UIViewController *fromVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey]; UIViewController *toVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey]; self.containerView = [transitionContext containerView]; UIView *fromView =[transitionContext viewForKey:UITransitionContextFromViewKey]; UIView *toView =[transitionContext viewForKey:UITransitionContextToViewKey]; [self.containerView addSubview:toView]; CGRect visibleFrame = [transitionContext initialFrameForViewController:fromVC]; CGRect rightHiddenFrame = CGRectMake( CGRectGetWidth(visibleFrame), 0,CGRectGetWidth(visibleFrame),CGRectGetHeight(visibleFrame)); CGRect leftHiddenFrame =CGRectMake(- CGRectGetWidth(visibleFrame), 0, CGRectGetWidth(visibleFrame), CGRectGetHeight(visibleFrame)); fromView.frame = visibleFrame; toView.frame = leftHiddenFrame; fromView.layer.masksToBounds = toView.layer.masksToBounds = YES; [UIView animateWithDuration:.5 animations:^{ fromView.frame = rightHiddenFrame; toView.frame = visibleFrame; } completion:^(BOOL finished) { if ([transitionContext transitionWasCancelled]) { [toView removeFromSuperview]; } [transitionContext completeTransition:![transitionContext transitionWasCancelled]]; }]; } @end
2.2、自定义交互手势
1》创建自定义文件
@interface CustonInteractive : UIPercentDrivenInteractiveTransition
因为UIPercentDrivenInteractiveTransition : NSObject <UIViewControllerInteractiveTransitioning>,所以自定义时继承遵循UIViewControllerInteractiveTransitioning协议的UIPercentDrivenInteractiveTransition子类!
2》相关文件:
#import <UIKit/UIKit.h> @interface CustonInteractive : UIPercentDrivenInteractiveTransition @property (nonatomic, assign) BOOL interacting; - (void)wireToViewController:(UIViewController*)viewController; @end
#import "CustonInteractive.h" @interface CustonInteractive() @property (nonatomic, strong) UIViewController *presentingVC; @end @implementation CustonInteractive -(void)wireToViewController:(UIViewController *)viewController { self.presentingVC = viewController; [self prepareGestureRecognizerInView:viewController.view]; } - (void)prepareGestureRecognizerInView:(UIView*)view { UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handleGesture:)]; [view addGestureRecognizer:gesture]; } - (void)handleGesture:(UIPanGestureRecognizer *)gestureRecognizer { CGFloat progress = [gestureRecognizer translationInView:gestureRecognizer.view.superview].x / (self.presentingVC.view.bounds.size.width * 1.0); progress = MIN(1.0, MAX(0.0, progress));//把这个百分比限制在0~1之间 NSLog(@"===%lf",progress); if (gestureRecognizer.state == UIGestureRecognizerStateBegan) { self.interacting = YES; [self.presentingVC dismissViewControllerAnimated:YES completion:nil]; } else if (gestureRecognizer.state == UIGestureRecognizerStateChanged){ if (self.interacting) { [self updateInteractiveTransition:progress]; } }else if (gestureRecognizer.state == UIGestureRecognizerStateCancelled||gestureRecognizer.state==UIGestureRecognizerStateEnded){ if (self.interacting) { if (progress>0.5) { [self finishInteractiveTransition]; }else{ [self cancelInteractiveTransition]; } self.interacting = NO; } } } @end
2.3、使用自定义转场动画
1》设置代理(以模态弹出为例)设置目标控制器的 transitioningDelegate
- (IBAction)present:(id)sender { PresentedViewController *vc = [[PresentedViewController alloc] init]; vc.transitioningDelegate = self; [_transitionController wireToViewController:vc]; [self presentViewController:vc animated:YES completion:nil]; }
附加:Navigation和TabBar代理设置(self.delegate = self)
2》实现UIViewControllerTransitioningDelegate代理方法
1 //设置弹出时动画协议 2 - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source; 3 //设置消失时动画协议 4 - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed; 5 //设置消失时手势协议 6 - (nullable id <UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id <UIViewControllerAnimatedTransitioning>)animator;
vc1的.m文件:
1 #import "PresentingViewController.h" 2 #import "CustomTransform.h" 3 #import "CustonInteractive.h" 4 #import "PresentedViewController.h" 5 6 7 #import "SecondTransform.h" 8 #import "SecondInteractive.h" 9 @interface PresentingViewController ()<UIViewControllerTransitioningDelegate,UINavigationControllerDelegate,UITabBarControllerDelegate>{ 10 SecondTransform *_presentAnimation; 11 SecondInteractive *_transitionController; 12 } 13 14 @end 15 16 @implementation PresentingViewController 17 18 - (void)viewDidLoad { 19 [super viewDidLoad]; 20 _presentAnimation = [SecondTransform new]; 21 _transitionController = [SecondInteractive new]; 22 // Do any additional setup after loading the view from its nib. 23 } 24 - (IBAction)present:(id)sender { 25 PresentedViewController *vc = [[PresentedViewController alloc] init]; 26 vc.transitioningDelegate = self; 27 [_transitionController wireToViewController:vc]; 28 [self presentViewController:vc animated:YES completion:nil]; 29 } 30 - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source 31 { 32 return _presentAnimation; 33 } 34 35 - (nullable id <UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed 36 { 37 return [SecondTransform makeWithTransitionType:PresentTransformAnimationTypeDismissed]; 38 } 39 40 -(id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator { 41 return _transitionController.isInterraction ? _transitionController : nil; 42 } 43 @end
Navigation和TabBar的代理方法:
#pragma mark---UINavigationControllerDelegate /* - (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController NS_AVAILABLE_IOS(7_0); - (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC NS_AVAILABLE_IOS(7_0); */ #pragma mark-UITabBarControllerDelegate /* - (nullable id <UIViewControllerInteractiveTransitioning>)tabBarController:(UITabBarController *)tabBarController interactionControllerForAnimationController: (id <UIViewControllerAnimatedTransitioning>)animationController NS_AVAILABLE_IOS(7_0); - (nullable id <UIViewControllerAnimatedTransitioning>)tabBarController:(UITabBarController *)tabBarController animationControllerForTransitionFromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC NS_AVAILABLE_IOS(7_0); */
ForeverGuard博客园