• Transition 过渡/转场动画(一)


    UIViewController 的转场效果

    当viewController通过push 或 present 进行转场时, 系统自带的动画是从右侧push进来一个新的viewControler (或从下面present 一个新的ViewController),  接下来我们要做的就是要自定义系统的这个动画效果. 

    原理: 比如当viewController  调用 dismiss 后, 系统会检查当前 vc 是否实现<UIViewControllerTransitioningDelegate> 协议, 该协议会返回 自定义 的转场动画

    例: 通过pan手势, dismiss 当前viewController

    1. 在调用dimiss的 VC 中实现 <UIViewControllerTransitioningDelegate> 协议

    
    #import "SecondViewController.h"
    #import "CustomInteractiveTransition.h"
    #import "CustomDissmissAnimation.h"
    
    @interface SecondViewController () <UIViewControllerTransitioningDelegate>
    
    @property (nonatomic, strong) CustomInteractiveTransition *interactiveAnimator;
    @property (nonatomic, strong) CustomDissmissAnimation *dismissAnimator;
    
    @end
    
    @implementation SecondViewController
    
    - (instancetype)init {
        if (self = [super init]) {
            self.transitioningDelegate = self;
        }
        return self;
    }
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        self.view.backgroundColor = [UIColor cyanColor];
        
        UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
        [button setTitle:@"dismiss" forState:UIControlStateNormal];
        button.frame = CGRectMake(100, 100, 100, 100);
        [button addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:button];
        
        self.interactiveAnimator = [[CustomInteractiveTransition alloc] initWithViewController:self];
        
        self.dismissAnimator = [[CustomDissmissAnimation alloc] init];
        
        UIPanGestureRecognizer *panGestureRecognizer =[[UIPanGestureRecognizer alloc] initWithTarget:self.interactiveAnimator action:@selector(panGestureAction:)];
        [self.view addGestureRecognizer:panGestureRecognizer];
        
        [self.transitionCoordinator notifyWhenInteractionEndsUsingBlock:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
            
        }];
    }
    
    - (void)viewWillAppear:(BOOL)animated {
        [super viewWillAppear:animated];
        
        [self.transitionCoordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
            UIView *view = [context viewForKey:UITransitionContextFromViewKey];
            view.transform = CGAffineTransformMakeScale(0.7, 0.7);
            
        } completion:^(id<UIViewControllerTransitionCoordinatorContext>  _Nonnull context) {
    //        UIView *view = [context viewForKey:UITransitionContextFromViewKey];
    //        view.transform = CGAffineTransformIdentity;
        }];
    }
    
    - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [self.transitionCoordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) { UIView *view = [context viewForKey:UITransitionContextToViewKey]; view.transform = CGAffineTransformMakeScale(1, 1); } completion:^(id<UIViewControllerTransitionCoordinatorContext> _Nonnull context) { // UIView *view = [context viewForKey:UITransitionContextToViewKey]; // view.transform = CGAffineTransformIdentity; }]; } - (void)dealloc { self.interactiveAnimator = nil; self.dismissAnimator = nil; } - (void)btnClick:(UIButton *)sender { [self dismissViewControllerAnimated:YES completion:nil]; } #pragma mark - UIViewControllerTransitioningDelegate // return 动画对象,该动画对象符合 UIViewControllerAnimatedTransitioning 协议,负责显示 present 动画。 - (id<UIViewControllerAnimatedTransitioning>)animationControllerForPresentedController:(UIViewController *)presented presentingController:(UIViewController *)presenting sourceController:(UIViewController *)source { return nil; } // return 动画对象,负责显示 dismiss 动画。 - (id<UIViewControllerAnimatedTransitioning>)animationControllerForDismissedController:(UIViewController *)dismissed { return self.dismissAnimator; } // return 交互式动画对象,该动画符合 UIViewControllerInteractiveTransitioning 协议,采用触摸手势或手势识别器作为动画的驱动,显示 present 动画。 - (id<UIViewControllerInteractiveTransitioning>)interactionControllerForPresentation:(id<UIViewControllerAnimatedTransitioning>)animator { return nil; } // return 交互式动画,显示 dismiss 动画 - (id<UIViewControllerInteractiveTransitioning>)interactionControllerForDismissal:(id<UIViewControllerAnimatedTransitioning>)animator { // 如果直接返回 interactive 会与系统的 dismiss 动画有冲突,导致点击 button 无法 dismiss 界面。 // 同时如果返回 interactiveAnimator,那么 animationControllerForDismissedController: 则必须实现 return self.interactiveAnimator.isInteractive? self.interactiveAnimator: nil; // return self.interactiveAnimator; } // return UIPresentationController,系统已经提供了各个演示样式。 //- (nullable UIPresentationController *)presentationControllerForPresentedViewController:(UIViewController *)presented presentingViewController:(UIViewController *)presenting sourceViewController:(UIViewController *)source NS_AVAILABLE_IOS(8_0); @end

    2. 实现一个动画对象, 实现 <UIViewControllerAnimatedTransitioning>协议

    - (NSTimeInterval)transitionDuration:(id<UIViewControllerContextTransitioning>)transitionContext {
        return 0.35f;
    }
    
    - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext {
        UIViewController *srcVC = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        
        UIViewController *secondVC = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
        
        UIView *containerView = [transitionContext containerView];
        
        [containerView addSubview:srcVC.view];
        
        [containerView addSubview:secondVC.view];
    
        [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
            secondVC.view.frame = CGRectMake(0, [UIScreen mainScreen].bounds.size.height, secondVC.view.bounds.size.width, secondVC.view.bounds.size.height);
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:!transitionContext.transitionWasCancelled];
        }];
    }

    3. 交互式动画效果, 需要实现<UIViewControllerInteractiveTransitioning>协议 ; 或者继承UIPercentDrivenInteractiveTransition 类

    * 可选实现. 在本例中, 通过pan手势下滑跟随dismiss, 需要通过交互式动画来实现

    #import "CustomInteractiveTransition.h"
    @interface CustomInteractiveTransition : UIPercentDrivenInteractiveTransition
    
    @property (nonatomic, assign, readonly) BOOL isInteractive;
    
    - (instancetype)initWithViewController:(UIViewController *)viewController;
    
    - (void)panGestureAction:(UIPanGestureRecognizer *)gestureRecognizer;
    
    @end
    //.m
    @interface CustomInteractiveTransition ()
    
    @property (nonatomic, weak) UIViewController *viewController;
    
    @property (nonatomic, assign) CGFloat startScale;
    
    @property (nonatomic, assign, readwrite) BOOL isInteractive;
    
    @end
    
    @implementation CustomInteractiveTransition
    
    - (instancetype)initWithViewController:(UIViewController *)viewController {
        if (self = [super init]) {
            _isInteractive = NO;
            _viewController = viewController;
        }
        return self;
    }
    
    - (void)panGestureAction:(UIPanGestureRecognizer *)recognizer {
        CGFloat progress = [recognizer translationInView:self.viewController.view].y / (self.viewController.view.bounds.size.height * 1.0);
        progress = MIN(1.0, MAX(0.0, progress));
        
        self.isInteractive = YES;
        
        if (recognizer.state == UIGestureRecognizerStateBegan) {
            
            [self.viewController dismissViewControllerAnimated:YES completion:^{
                
            }];
        }
        else if (recognizer.state == UIGestureRecognizerStateChanged) {
            [self updateInteractiveTransition:progress];
        }
        else if (recognizer.state == UIGestureRecognizerStateEnded || recognizer.state == UIGestureRecognizerStateCancelled) {
            if (progress > 0.5) {
                [self finishInteractiveTransition];
            }
            else {
                [self cancelInteractiveTransition];
            }
            
            self.isInteractive = NO;
        }
    }
    
    @end

    在 iOS中,可以取消一个过渡。这意味着,第二个视图的 -viewWillApear 被调用,但 -viewDidApear不一定被调用。
    如果代码写的假定 -viewDidAppear 总是在 -viewWillAppear 之后执行则需要重新考虑逻辑实现。
    这种情况下UIViewControllerTransitionCoordinator 就有用了。在交互式过渡结束的时候,会在 block 中收到通知。

    参考:

    present:   https://www.jianshu.com/p/aed8a3a15c82

    push/pop: https://www.jianshu.com/p/28b9523d70a9

  • 相关阅读:
    CentOS 6.3用ssh无密码登陆其它主机
    堆排序算法以及JAVA实现
    TaskTracker发送Heartbeat以及接受HeartbeatResponse
    Linux常用命令总结
    用eclipse将mapreduce程序打成jar包并在命令行执行
    jquery自定义验证方法
    solaris中几个网络经典命令小结
    DWR的简单总结[转]
    java 编码问题 及转换
    DWR学习详解【转】
  • 原文地址:https://www.cnblogs.com/daxueshan/p/11672113.html
Copyright © 2020-2023  润新知