导航控制器自定义过渡动画 [英] Navigation controller custom transition animation

查看:133
本文介绍了导航控制器自定义过渡动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在使用一些教程来创建自定义动画,同时从一个视图转换到另一个视图。



我的测试项目使用自定义segue从这里工作正常,但有人告诉我,不鼓励在自定义segue做自定义动画,我应该使用 UIViewControllerAnimatedTransitioning



我跟着几个使用这个协议的教程,但是他们都是关于模态演示例如本教程)。



我要做什么是一个在导航控制器树内的推动segue,但是当我尝试做同样的事情与显示(推)segue它不工作了。



请告诉我在导航控制器中从一个视图到另一个视图执行自定义转换动画的正确方法。



还有,我可以使用一种方法来转换动画吗?如果有一天我想做同样的动画,但是最终不得不复制代码两次,以工作在模态vs控制器转换。这将是尴尬的。

解决方案

要使用导航控制器( UINavigationController )进行自定义转换,您应该:




  • 定义视图控制器以符合 UINavigationControllerDelegate 协议。例如,您可以在视图控制器的 .m 文件中具有指定与此协议一致的专用类扩展:

      @interface ViewController()< UINavigationControllerDelegate> 

    @end


  • 确保您实际指定了视图控制器作为您的导航控制器的委托:

       - (void)viewDidLoad {
    [super viewDidLoad];

    self.navigationController.delegate = self;
    }


  • 实施 animationControllerForOperation in your view controller:

       - (id< UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController 
    animationControllerForOperation :(UINavigationControllerOperation)操作
    fromViewController:(UIViewController *)fromVC
    toViewController:(UIViewController *)toVC
    {
    if(operation == UINavigationControllerOperationPush)
    return [ PushAnimator alloc] init];

    if(operation == UINavigationControllerOperationPop)
    return [[PopAnimator alloc] init];

    return nil;
    }


  • 实现推送和流行动画的动画制作,例如:

      @interface PushAnimator:NSObject< UIViewControllerAnimatedTransitioning> 

    @end

    @interface PopAnimator:NSObject< UIViewControllerAnimatedTransitioning>

    @end

    @implementation PushAnimator

    - (NSTimeInterval)transitionDuration:(id< UIViewControllerContextTransitioning>)transitionContext
    {
    return 0.5;
    }

    - (void)animateTransition:(id< UIViewControllerContextTransitioning>)transitionContext
    {
    UIViewController * toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];

    [[transitionContext containerView] addSubview:toViewController.view];

    toViewController.view.alpha = 0.0;

    [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^ {
    toViewController.view.alpha = 1.0;
    } completion:^(BOOL finished){
    [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
    }];
    }

    @end

    @implementation PopAnimator

    - (NSTimeInterval)transitionDuration:(id< UIViewControllerContextTransitioning>)transitionContext
    {
    return 0.5;
    }

    - (void)animateTransition:(id< UIViewControllerContextTransitioning>)transitionContext
    {
    UIViewController * toViewController = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    UIViewController * fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];

    [[transitionContext containerView] insertSubview:toViewController.view belowSubview:fromViewController.view];

    [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^ {
    fromViewController.view.alpha = 0.0;
    } completion:^(BOOL finished){
    [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
    }];
    }

    @end


  • 如果您想要处理交互式手势(例如,从左到右你必须实现一个交互控制器:




    • 定义一个交互控制器的属性 UIViewControllerInteractiveTransitioning ):

        @property(nonatomic,strong)UIPercentDrivenInteractiveTransition * interactionController ; 

      这个 UIPercentDrivenInteractiveTransition


    • 在视图中添加手势识别器。这里我只是实现左手势识别器来模拟流行:

        UIScreenEdgePanGestureRecognizer * edge = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget: self action:@selector(handleSwipeFromLeftEdge :)]; 
      edge.edges = UIRectEdgeLeft;
      [view addGestureRecognizer:edge];


    • 实现手势识别器处理程序:

        / **从左边缘处理滑动
      *
      *这是当左边屏幕边缘手势识别器启动时调用的动作选择器。
      *
      *当手势开始时,将实例化一个UIPercentDrivenInteractiveTransition,
      *更新它为手势更改,并且当手势
      *结束时完成并释放它。
      *
      * @param gesture屏幕边缘平移手势识别器。
      * /

      - (void)handleSwipeFromLeftEdge:(UIScreenEdgePanGestureRecognizer *)gesture {
      CGPoint translate = [gesture translationInView:gesture.view];
      CGFloat percent = translate.x / gesture.view.bounds.size.width;

      if(gesture.state == UIGestureRecognizerStateBegan){
      self.interactionController = [[UIPercentDrivenInteractiveTransition alloc] init];
      [self popViewControllerAnimated:TRUE];
      } else if(gesture.state == UIGestureRecognizerStateChanged){
      [self.interactionController updateInteractiveTransition:percent];
      } else if(gesture.state == UIGestureRecognizerStateEnded){
      CGPoint velocity = [gesture velocityInView:gesture.view];
      if(percent> 0.5 || velocity.x> 0){
      [self.interactionController finishInteractiveTransition];
      } else {
      [self.interactionController cancelInteractiveTransition];
      }
      self.interactionController = nil;
      }
      }


    • 在导航控制器委派中,必须实现 interactionControllerForAnimationController 委托方法

         - (id< UIViewControllerInteractiveTransitioning> navigationController:(UINavigationController *)navigationController 
      interactionControllerForAnimationController:(id< UIViewControllerAnimatedTransitioning>)animationController {
      return self.interactionController;
      }





如果你googleUINavigationController自定义转换教程,你会得到很多命中。或者,请参阅 WWDC 2013自定义转场视频


I've been following some tutorials to create custom animation while transitioning from one view to another.

My test project using custom segue from here works fine, but someone told me it's not encouraged anymore to do custom animation within a custom segue, and I should use UIViewControllerAnimatedTransitioning.

I followed several tutorials that make use of this protocol, but all of them are about modal presentation (for example this tutorial).

What I'm trying to do is a push segue inside a navigation controller tree, but when I try to do the same thing with a show (push) segue it doesn't work anymore.

Please tell me the correct way to do custom transitioning animation from one view to another in a navigation controller.

And is there anyway I can use one method for all transitioning animations? It would be awkward if one day I want to do the same animation but end up having to duplicate the code twice to work on modal vs controller transitioning.

解决方案

To do a custom transition with navigation controller (UINavigationController), you should:

  • Define your view controller to conform to UINavigationControllerDelegate protocol. For example, you can have a private class extension in your view controller's .m file that specifies conformance to this protocol:

    @interface ViewController () <UINavigationControllerDelegate>
    
    @end
    

  • Make sure you actually specify your view controller as your navigation controller's delegate:

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.navigationController.delegate = self;
    }
    

  • Implement animationControllerForOperation in your view controller:

    - (id<UIViewControllerAnimatedTransitioning>)navigationController:(UINavigationController *)navigationController
                                      animationControllerForOperation:(UINavigationControllerOperation)operation
                                                   fromViewController:(UIViewController*)fromVC
                                                     toViewController:(UIViewController*)toVC
    {
        if (operation == UINavigationControllerOperationPush)
            return [[PushAnimator alloc] init];
    
        if (operation == UINavigationControllerOperationPop)
            return [[PopAnimator alloc] init];
    
        return nil;
    }
    

  • Implement animators for push and pop animations, e.g.:

    @interface PushAnimator : NSObject <UIViewControllerAnimatedTransitioning>
    
    @end
    
    @interface PopAnimator : NSObject <UIViewControllerAnimatedTransitioning>
    
    @end
    
    @implementation PushAnimator
    
    - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
    {
        return 0.5;
    }
    
    - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
    {
        UIViewController* toViewController   = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
    
        [[transitionContext containerView] addSubview:toViewController.view];
    
        toViewController.view.alpha = 0.0;
    
        [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
            toViewController.view.alpha = 1.0;
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
        }];
    }
    
    @end
    
    @implementation PopAnimator
    
    - (NSTimeInterval)transitionDuration:(id <UIViewControllerContextTransitioning>)transitionContext
    {
        return 0.5;
    }
    
    - (void)animateTransition:(id<UIViewControllerContextTransitioning>)transitionContext
    {
        UIViewController* toViewController   = [transitionContext viewControllerForKey:UITransitionContextToViewControllerKey];
        UIViewController* fromViewController = [transitionContext viewControllerForKey:UITransitionContextFromViewControllerKey];
    
        [[transitionContext containerView] insertSubview:toViewController.view belowSubview:fromViewController.view];
    
        [UIView animateWithDuration:[self transitionDuration:transitionContext] animations:^{
            fromViewController.view.alpha = 0.0;
        } completion:^(BOOL finished) {
            [transitionContext completeTransition:![transitionContext transitionWasCancelled]];
        }];
    }
    
    @end
    

    That does fade transition, but you should feel free to customize the animation as you see fit.

  • If you want to handle interactive gestures (e.g. something like the native swipe left-to-right to pop), you have to implement an interaction controller:

    • Define a property for an interaction controller (an object that conforms to UIViewControllerInteractiveTransitioning):

      @property (nonatomic, strong) UIPercentDrivenInteractiveTransition *interactionController;
      

      This UIPercentDrivenInteractiveTransition is a nice object that does the heavy lifting of updating your custom animation based upon how complete the gesture is.

    • Add a gesture recognizer to your view. Here I'm just implementing the left gesture recognizer to simulate a pop:

      UIScreenEdgePanGestureRecognizer *edge = [[UIScreenEdgePanGestureRecognizer alloc] initWithTarget:self action:@selector(handleSwipeFromLeftEdge:)];
      edge.edges = UIRectEdgeLeft;
      [view addGestureRecognizer:edge];
      

    • Implement the gesture recognizer handler:

      /** Handle swipe from left edge
       *
       * This is the "action" selector that is called when a left screen edge gesture recognizer starts.
       *
       * This will instantiate a UIPercentDrivenInteractiveTransition when the gesture starts,
       * update it as the gesture is "changed", and will finish and release it when the gesture
       * ends.
       *
       * @param   gesture       The screen edge pan gesture recognizer.
       */
      
      - (void)handleSwipeFromLeftEdge:(UIScreenEdgePanGestureRecognizer *)gesture {
          CGPoint translate = [gesture translationInView:gesture.view];
          CGFloat percent   = translate.x / gesture.view.bounds.size.width;
      
          if (gesture.state == UIGestureRecognizerStateBegan) {
              self.interactionController = [[UIPercentDrivenInteractiveTransition alloc] init];
              [self popViewControllerAnimated:TRUE];
          } else if (gesture.state == UIGestureRecognizerStateChanged) {
              [self.interactionController updateInteractiveTransition:percent];
          } else if (gesture.state == UIGestureRecognizerStateEnded) {
              CGPoint velocity = [gesture velocityInView:gesture.view];
              if (percent > 0.5 || velocity.x > 0) {
                  [self.interactionController finishInteractiveTransition];
              } else {
                  [self.interactionController cancelInteractiveTransition];
              }
              self.interactionController = nil;
          }
      }
      

    • In your navigation controller delegate, you also have to implement interactionControllerForAnimationController delegate method

      - (id<UIViewControllerInteractiveTransitioning>)navigationController:(UINavigationController *)navigationController
                               interactionControllerForAnimationController:(id<UIViewControllerAnimatedTransitioning>)animationController {
          return self.interactionController;
      }
      

If you google "UINavigationController custom transition tutorial" and you'll get many hits. Or see WWDC 2013 Custom Transitions video.

这篇关于导航控制器自定义过渡动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆