视图控制器转换(View Controller Transition) 俗称 关于转场动画
UINavigationController 的 push pop 转场动画
视图控制器中的视图显示在屏幕上有两种方式:最主要的方式是内嵌在容器控制器中,比如 UINavigationController,UITabBarController, UISplitController;由另外一个视图控制器显示它,这种方式通常被称为模态(Modal)显示。View Controller Transition 是什么?在 NavigationController 里 push 或 pop 一个 View Controller,在 TabBarController 中切换到其他 View Controller,以 Modal 方式显示另外一个 View Controller,这些都是 View Controller Transition。
首先放个官方链接以示正式
官方支持的可以自定义的转场动画
- UINavigationController 的 push pop 转场动画
- UIViewController 的 present dissmiss 转场动画。仅限于modalPresentationStyle属性为 UIModalPresentationFullScreen 或 UIModalPresentationCustom 这两种模式
- UITabBarController 中切换 Tab 转场动画
- UICollectionViewController 的布局转场 UICollectionViewController 与 UINavigationController 结合的转场方式
Push & Pop
首先介绍一下系统方法:
主要会涉及到两个UINavigationController的代理
解释下fromVC & toVC —-> 如果是从A视图控制器push到B,则A是fromVC,B是toVC。从B视图控制器pop到A时,B变成了fromVC,A是toVC123456789看返回参数 这是个返回动画的代理- (nullable id <UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationControlleranimationControllerForOperation:(UINavigationControllerOperation)operationfromViewController:(UIViewController *)fromVCtoViewController:(UIViewController *)toVC NS_AVAILABLE_IOS(7_0);看返回参数 这是个交互代理 就是手势驱动了- (nullable id <UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationControllerinteractionControllerForAnimationController:(id <UIViewControllerAnimatedTransitioning>) animationController NS_AVAILABLE_IOS(7_0);既然动画是 返回
的id类型的类 那我们看下 这个代理是什么 1234返回动画执行时间- (NSTimeInterval)transitionDuration:(nullable id <UIViewControllerContextTransitioning>)transitionContext;关于自定义动画就要在这里操作了- (void)animateTransition:(id <UIViewControllerContextTransitioning>)transitionContext;再看下交互代理有什么 UIViewControllerInteractiveTransitioning
12345678系统有这个类是遵循这个交互代理的 我们只要继承这个类就行了NS_CLASS_AVAILABLE_IOS(7_0) @interface UIPercentDrivenInteractiveTransition : NSObject <UIViewControllerInteractiveTransitioning>关于这个类的几个重要的方法- (void)pauseInteractiveTransition NS_AVAILABLE_IOS(10_0);- (void)updateInteractiveTransition:(CGFloat)percentComplete;- (void)cancelInteractiveTransition;- (void)finishInteractiveTransition;
至此 所有用到的类及方法简单的介绍了 Let’s do it
我的实现目的是为了省化系统的一堆代理,就算你不知道有哪些代理一样能自定义转场动画。
关于UINavigationController的处理:可以在自定义的baseNav里做处理 也可以建个UINavigationController的Category
123456789101112131415161718
利用runtime 做个方法替换+ (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Method sysPush = class_getInstanceMethod(self.class, @selector(pushViewController:animated:)); Method dfPush = class_getInstanceMethod(self.class, @selector(df_pushViewController:animated:)); method_exchangeImplementations(sysPush, dfPush); });} 目的的话当然是设置代理了 要不然 动画怎么走- (void)df_pushViewController:(UIViewController *)viewController animated:(BOOL)animated {// 为了适用一些情况 考虑之后 这里的判断我去掉了// if ([viewController conformsToProtocol:@protocol(DFTransitionProtocol)]) { self.delegate = (id<UINavigationControllerDelegate>)viewController;// } [self df_pushViewController:viewController animated:animated]; }
关于UIViewController的处理:可以在自定义的baseVC里做处理 也可以建个UIViewController的Category (初始想法是把nav的代理指定到自定义的NSObject的,不在UIViewController的Category里面操作的。也不知道为什么就没按意愿走)
12345678910111213141516
这里的操作除了实现Nav的两个代理之外还要做些操作 nav的push里面虽然指定了代理 但是pop回来的时候代理就丢了 解决方案2选1: 1:替换nav的pop方法重新指定代理 2:替换vc的appear方法重新指定代理+ (void)load { static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ Method sysdidDisappear = class_getInstanceMethod(self.class, @selector(viewDidAppear:)); Method dfdidDisappear = class_getInstanceMethod(self.class, @selector(df_viewDidAppear:)); method_exchangeImplementations(sysdidDisappear, dfdidDisappear); });}- (void)df_viewDidAppear:(BOOL)animated { self.navigationController.delegate = self; [self df_viewDidAppear:animated];}
关于动画 @interface DFBaseTransitionAnimation : NSObject
只要继承这个类重写动画的两个方法 就可以实现自己的自定义动画了
关于手势驱动类 @interface DFInteractiveTransition : UIPercentDrivenInteractiveTransition 里面都做了处理了 详细就看工程吧 最后会附上工程demo
关于使用
使用很简单 只要vc 遵守
自定义动画要继承自 DFBaseTransitionAnimation
如果不实现 那么返回的是DFBaseTransitionAnimation 这个里面的默认动画
手势的话也是默认手势 详情看协议
12
- (DFBaseTransitionAnimation *)pushTransitionAnimation;- (DFBaseTransitionAnimation *)popTransitionAnimation;
最后说下坑
首先说下vc返回释放不了的问题,起初以为是delegate造成的没释放,后来发现是因为手势里面对VC进行了强持有引起的
系统nav有个返回的手势 重写代理之后就不能用了 不知道应该是这样的还是我写的有错误的问题
动画里面 用UIView的动画转场 可以手势百分比 当用CATransition 做layer动画的时候 返回手势就不能百分比