ProgramingTip

탐색 컨트롤러 사용자 지정 전환 애니메이션

bestdevel 2020. 10. 25. 12:42
반응형

탐색 컨트롤러 사용자 지정 전환 애니메이션


한보 기에서 다른보기로 전환하는 동안 사용자 지정 애니메이션을 만들기 위해 몇 가지 안내를 따라 왔습니다.

여기 에서 사용자 지정 프로그램을 사용하는 내 지정 테스트 프로젝트 는 잘 작동하지만 누군가가 사용자 지정 프로그램 내에서 사용자 지정 애니메이션을 수행하는 것이 더 이상 권장되지 않습니다 UIViewControllerAnimatedTransitioning.

이 프로토콜을 사용하는 여러 안내를 따랐지만 모두 모달 프레젠테이션에 관한 것입니다 (예 : 이 안내 ).

내가 시도하려는 것은 내비게이션 컨트롤러 트리 내부의 푸시 세그이지만 쇼 (푸시) 세그로 동일한 작업을 시도하면 더 이상 작동하지 않습니다.

내비게이션 컨트롤러에서 한보 기에서 다른보기로 사용자 지정 전환 애니메이션을 수행하는 올바른 방법을 알려주세요.

그리고 모든 어쨌든 전환 애니메이션에 대해 하나의 방법을 사용할 수 있습니까? 언젠가 동일한 애니메이션을 싶지만 모달 대 컨트롤러 전환 작업을 위해 코드를 두 번 복제해야한다면 어색 할 것입니다.


탐색 컨트롤러 ( 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 사용자 지정 전환 안내"를 Google에 검색하면 많은 히트를 얻을 수 있습니다. 또는 WWDC 2013 Custom Transitions 비디오를 참조하십시오 .


전에 다음 코드를 추가하고 싶을 수 있습니다. addSubview

  toViewController.view.frame = [transitionContext finalFrameForViewController:toViewController];

다른 질문에서 custom-transition-for-push-animation-with-navigationcontroller-on-ios-9

finalFrameForViewController에 대한 Apple의 문서에서 :

지정된 뷰 컨트롤러의 뷰에 대한 종료 프레임 사각형을 반환합니다.

이 메서드가 반환하는 사각형은 전환이 끝날 때 해당 뷰의 크기를 나타냅니다. 프레젠테이션 중에 다루는 뷰의 경우이 메서드에서 반환 된 값은 CGRectZero 일 수 있지만 유효한 프레임 사각형 일 수도 있습니다.


Rob 's & Q i의 완벽한 답변을 사용하면 .push 및 .pop에 대해 동일한 페이드 애니메이션을 사용하는 단순화 된 Swift 코드가 있습니다.

extension YourViewController: UINavigationControllerDelegate {
    func navigationController(_ navigationController: UINavigationController,
                              animationControllerFor operation: UINavigationControllerOperation,
                              from fromVC: UIViewController,
                              to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {

        //INFO: use UINavigationControllerOperation.push or UINavigationControllerOperation.pop to detect the 'direction' of the navigation

        class FadeAnimation: NSObject, UIViewControllerAnimatedTransitioning {
            func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
                return 0.5
            }

            func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
                let toViewController = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)
                if let vc = toViewController {
                    transitionContext.finalFrame(for: vc)
                    transitionContext.containerView.addSubview(vc.view)
                    vc.view.alpha = 0.0
                    UIView.animate(withDuration: self.transitionDuration(using: transitionContext),
                    animations: {
                        vc.view.alpha = 1.0
                    },
                    completion: { finished in
                        transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
                    })
                } else {
                    NSLog("Oops! Something went wrong! 'ToView' controller is nill")
                }
            }
        }

        return FadeAnimation()
    }
}

YourViewController의 viewDidLoad () 메서드에서 대리자를 설정하는 것을 잊지 마십시오.

override func viewDidLoad() {
    //...
    self.navigationController?.delegate = self
    //...
}

그것은 빠른 3과 4 모두 작동합니다

    @IBAction func NextView(_ sender: UIButton) {
        let newVC = self.storyboard?.instantiateViewControllerWithIdentifier(withIdentifier: "NewVC") as! NewViewController

                let transition = CATransition()
                transition.duration = 0.5
                transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
                transition.type = kCATransitionPush
                transition.subtype = kCAGravityLeft
    //instead "kCAGravityLeft" try with different transition subtypes

        self.navigationController?.view.layer.add(transition, forKey: kCATransition)
        self.navigationController?.pushViewController(newVC, animated: false)

            }

참고 URL : https://stackoverflow.com/questions/26569488/navigation-controller-custom-transition-animation

반응형