1. ホーム
  2. ios

ナビゲーションコントローラーのカスタムトランジションアニメーション

2023-09-10 15:30:28

質問

あるビューから別のビューに遷移する際に、カスタムアニメーションを作成するためにいくつかのチュートリアルを見てきました。

カスタムセグエを使用した私のテストプロジェクトは ここで はうまく動きますが、ある人が、カスタムセグエの中でカスタムアニメーションを行うことはもう推奨されないと教えてくれたので、カスタムセグエを使用するには UIViewControllerAnimatedTransitioning .

このプロトコルを利用したチュートリアルをいくつか追ってみましたが、どれもモーダルプレゼンテーションに関するものでした(たとえば このチュートリアル ).

私がやろうとしているのは、ナビゲーションコントローラツリー内のプッシュセグですが、同じことをショー(プッシュ)セグでやろうとすると、もううまくいきません。

ナビゲーションコントローラのあるビューから別のビューへのカスタム遷移アニメーションを行うための正しい方法を教えてください。

また、すべての遷移アニメーションに1つのメソッドを使用できる方法はありますか?ある日、同じアニメーションを行いたいのに、モーダルとコントローラの遷移のためにコードを2回複製しなければならなくなったら、困ります。

どのように解決するのですか?

ナビゲーション・コントローラでカスタムトランジションを行うには ( UINavigationController ) を使用する必要があります。

  • に適合するようにビューコントローラを定義します。 UINavigationControllerDelegate プロトコルに準拠するように定義します。たとえば、プライベートクラスの拡張子をビューコントローラの .m ファイルで、このプロトコルへの準拠を指定することができます。

    @interface ViewController () <UINavigationControllerDelegate>
    
    @end
    
    
  • ナビゲーションコントローラのデリゲートとして、実際にビューコントローラを指定することを確認してください。

    - (void)viewDidLoad {
        [super viewDidLoad];
    
        self.navigationController.delegate = self;
    }
    
    
  • 実装 animationControllerForOperation をビューコントローラに実装します。

    - (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;
    }
    
    
  • プッシュ・ポップ・アニメーションのためのアニメーターを実装する、など。

    @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];
      
      
    • ジェスチャー認識ハンドラを実装します。

      /** 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;
          }
      }
      
      
    • ナビゲーション・コントローラーのデリゲートでは、さらに interactionControllerForAnimationController デリゲートメソッド

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

UINavigationController custom transition tutorial"でググるとたくさんヒットしますよ。あるいは WWDC 2013 カスタム トランジション ビデオ .