一 学习 在 UINavigationController 中 push 和 pop 的转场效果
(基于iOS7 以上的转场方式)
- 经过学习了解到,重点分三块:
- (1)pushAnimation: TransitionPushAnimation 进场效果动画管理器 (NSObject并遵守UIViewControllerAnimatedTransitioning协议)
- (2)popAnimation: TransitionPopAnimation 出场效果动画管理器 (NSObject并遵守UIViewControllerAnimatedTransitioning协议)
- (3)navigationPerformerObject: TransitionNavigationPerformer 对象操控转场 (设置转场动画代理遵从 UINavigationControllerDelegate协议)
- (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext
- (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
注意要点: 判断 动画执行完成结果状态
当用户做手指跟随操作的过程中,根据操作的finished位置 要判断此时应该是该结束动画 还是取消动画.
[transitionContext completeTransition:![transitionContext transitionWasCancelled]];
下面手势 就是 判断用户手势跟随进度 :
if ( progress > 0.5) {// 时为 完成 触发"返回"操作
[self.interactionController finishInteractiveTransition];//transitionContext.transitionWasCancelled 会得到NO的回调
} else {// 反之 为取消 保留当前页面
[self.interactionController cancelInteractiveTransition];//transitionContext.transitionWasCancelled 会得到YES的回调
}
起初因为 [transitionContext transitionWasCancelled] 状态没注意导致 页面过渡 就那么卡住了 或者 页面空白,种种动画效果滞涩的问题都是 状态信号控制不好导致的
- (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);
通常写法是把导航去设置和代理方法写在对应的视图控制器里面,这里我们创建 一个对象TransitionNavigationPerformer 遵循UINavigationControllerDelegate代理方法,这样封装,耦合性低,并且代码可移植性更强.
#import <Foundation/Foundation.h> @class TransitionPushAnimation; @class TransitionPopAnimation; @interface TransitionNavigationPerformer : NSObject <UINavigationControllerDelegate> - (instancetype)initWithNav:(id)nav; //为了操控 self.navigationController @property (weak, nonatomic) UINavigationController *navigationController; //这里强调单项弱引用 @property (strong, nonatomic) TransitionPushAnimation *pushAnimation; @property (strong, nonatomic) TransitionPopAnimation *popAnimation; @property (strong, nonatomic) UIPercentDrivenInteractiveTransition *interactionController;//没做特殊处理 就是默认系统创建 用来控制动画效果进度状态 @end
// // TransitionNavigationPerformer.m // SectionDemo // // Created by HF on 17/3/29. // Copyright © 2017年 HF-Liqun. All rights reserved. // #import "TransitionNavigationPerformer.h" #import "TransitionPopAnimation.h" #import "TransitionPushAnimation.h" @interface TransitionNavigationPerformer () { UIScreenEdgePanGestureRecognizer *panGesture; } @end @implementation TransitionNavigationPerformer - (instancetype)initWithNav:(id)nav { self = [super init]; if (self) { self.navigationController = nav; // 在导航控制器的视图上添加pan手势 --> 需要从边缘进行拖动,在控制器转换的时候是有用 "UIScreenEdgePanGestureRecognizer" panGesture = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(pan:)]; panGesture.edges = UIRectEdgeLeft; //主要用作返回 left [self.navigationController.view addGestureRecognizer:panGesture]; // 初始化动画方案 self.pushAnimation = [[TransitionPushAnimation alloc] init]; self.popAnimation = [[TransitionPopAnimation alloc] init]; } return self; } - (void)dealloc { //这里目的防止取消切换效果后 导航控制器仍然会对手势持有 [panGesture removeTarget:self action:@selector(pan:)]; self.interactionController = nil; } - (void)pan:(UIScreenEdgePanGestureRecognizer *)recognizer { UIView *view = self.navigationController.view; CGFloat progress = [recognizer translationInView:view].x / (view.bounds.size.width * 1.0); progress = MIN(1.0, MAX(0.0, progress)); if (recognizer.state == UIGestureRecognizerStateBegan) { // 创建过渡对象,弹出viewController self.interactionController = [[UIPercentDrivenInteractiveTransition alloc] init]; [self.navigationController popViewControllerAnimated:YES]; } else if (recognizer.state == UIGestureRecognizerStateChanged) { // 更新 interactive transition 的进度 [self.interactionController updateInteractiveTransition:progress]; } else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled) { // 完成或者取消过渡 if (progress > 0.5) { [self.interactionController finishInteractiveTransition]; } else { [self.interactionController cancelInteractiveTransition]; } self.interactionController = nil; } } #pragma mark - UINavigationControllerDelegate - (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController animationControllerForOperation:(UINavigationControllerOperation)operation fromViewController:(UIViewController *)fromVC toViewController:(UIViewController *)toVC { if (operation == UINavigationControllerOperationPush) { return self.pushAnimation; } else if (operation == UINavigationControllerOperationPop) { return self.popAnimation; } return nil; } - (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController { // 检查是否是我们的自定义过渡 if ([animationController isKindOfClass:[TransitionPushAnimation class]] || [animationController isKindOfClass:[TransitionPopAnimation class]]) { return self.interactionController; } else { return nil; } }
@end
3 方法调用
(1)在使用的时候 要添加self.navigationController.delegate = TransitionNavigationPerformer 对象, 不需要就设置为nil
(2)页面viewWillDisappear 一定要立即取消代理方法 防止交互崩溃 .
参考Demo:SectionDemo
效果:
参考:
http://www.open-open.com/lib/view/open1408677710366.html
http://www.cocoachina.com/ios/20150811/12986.html
https://github.com/seedante/iOS-Note/wiki/ViewController-Transition