[TIL] UIViewControllerTransitioningDelegate

Eden·2025년 9월 17일

iOS에서 뷰 컨트롤러 전환(Modal, Present/Dismiss)을 커스텀 애니메이션으로 제어하려면
UIViewControllerTransitioningDelegate 프로토콜을 사용한다.


1. 기본 개념

  • Modal 전환 시 기본 제공되는 애니메이션(아래에서 위로 올라오기 등)을 개발자가 직접 정의할 수 있게 해준다.
  • UIViewControllerTransitioningDelegate는 전환 과정에서 사용할 객체(애니메이터, 인터랙션 컨트롤러 등)를 반환한다.

2. 주요 메서드

protocol UIViewControllerTransitioningDelegate : AnyObject {
    func animationController(forPresented presented: UIViewController,
                             presenting: UIViewController,
                             source: UIViewController) -> UIViewControllerAnimatedTransitioning?

    func animationController(forDismissed dismissed: UIViewController)
        -> UIViewControllerAnimatedTransitioning?

    func interactionControllerForPresentation(using animator: UIViewControllerAnimatedTransitioning)
        -> UIViewControllerInteractiveTransitioning?

    func interactionControllerForDismissal(using animator: UIViewControllerAnimatedTransitioning)
        -> UIViewControllerInteractiveTransitioning?
}

역할 요약

  • animationController(forPresented:)
    • Present 시 사용할 애니메이터 객체 반환
  • animationController(forDismissed:)
    • Dismiss 시 사용할 애니메이터 객체 반환
  • interactionControllerForPresentation(using:)
    • 제스처 기반 인터랙션 전환(Pan, Swipe 등) 컨트롤러 반환
  • interactionControllerForDismissal(using:)
    • Dismiss 제스처 기반 인터랙션 컨트롤러 반환

3. 애니메이터 정의 (UIViewControllerAnimatedTransitioning)

UIViewControllerAnimatedTransitioning실제 애니메이션 동작을 정의하는 프로토콜이다.

class CustomAnimator: NSObject, UIViewControllerAnimatedTransitioning {
    let duration = 0.3

    func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
        return duration
    }

    func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
        guard let toView = transitionContext.view(forKey: .to) else { return }
        let container = transitionContext.containerView

        // 초기 상태 (아래에서 시작)
        toView.transform = CGAffineTransform(translationX: 0, y: container.bounds.height)
        container.addSubview(toView)

        // 애니메이션
        UIView.animate(withDuration: duration, animations: {
            toView.transform = .identity
        }, completion: { finished in
            transitionContext.completeTransition(finished)
        })
    }
}

4. TransitioningDelegate 구현

class CustomTransitioningDelegate: NSObject, UIViewControllerTransitioningDelegate {
    let animator = CustomAnimator()

    func animationController(forPresented presented: UIViewController,
                             presenting: UIViewController,
                             source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return animator
    }

    func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
        return animator
    }
}

5. 사용 예시

let vc = DetailViewController()
let customDelegate = CustomTransitioningDelegate()

vc.modalPresentationStyle = .custom
vc.transitioningDelegate = customDelegate

present(vc, animated: true, completion: nil)
  • modalPresentationStyle = .custom을 반드시 지정해야 한다.
  • transitioningDelegate에 커스텀 델리게이트를 할당해야 커스텀 전환이 적용된다.

6. 확장 기능

  • UIViewControllerInteractiveTransitioning
    • 사용자가 제스처로 전환 속도를 조절할 수 있게 한다. (예: 스와이프 시 진행률 따라 애니메이션)
  • UIPercentDrivenInteractiveTransition
    • 제스처 진행률에 따라 전환 애니메이션을 제어하는 기본 구현 제공
  • UIViewControllerContextTransitioning
    • 전환 중 컨텍스트(컨테이너 뷰, from/to 뷰, 전환 완료 여부)를 제공

7. 정리

  • UIViewControllerTransitioningDelegate애니메이션/인터랙션 객체를 연결하는 다리 역할이다.
  • 실제 애니메이션은 UIViewControllerAnimatedTransitioning이 담당한다.
  • 인터랙션 전환을 추가하려면 UIPercentDrivenInteractiveTransition 등을 활용한다.
  • 적용하려면 modalPresentationStyle = .customtransitioningDelegate 설정이 필요하다.
profile
iOS Dev

0개의 댓글