iOS) Custom Transition

Havi·2021년 4월 16일
0

오늘은 화려한 화면이동을 위해 커스텀 화면전환 애니메이션에 대해 공부해보려 한다.

공식 문서
UIViewControllerAnimatedTransitioning
UIPercentDrivenInteractiveTransition
UIViewControllerTransitioningDelegate

참고 블로그
레이웬더리치
고무망치님 블로그
남스님 블로그

UIViewControllerAnimatedTransitioning

custom view controller transition을 implement하기 위한 Protocol이다.

해당 프로토콜은

  1. 화면 전환의 Duration을 정의해주는 func transitionDuration(using:)
  2. Animator객체가 애니메이션을 만들 수 있게하는func animateTransition(using :)

을 필수로 구현해야 한다.

보통 Animation을 담당하는 클래스가 준수한다.

UIPercentDrivenInteractiveTransition

ViewController과 다른 View간의 interactive한 animation을 발생시키는 Class이다.

UIViewControllerTransitioningDelegate

ViewController간의 interactive한 transition을 관리하는 Protocol이다.

화면을 이동하는 ViewController에서 구현해준다.

1) Animation담당 클래스 설정

먼저 Animation을 처리할 클래스를 선언해야한다.

UIViewControllerAnimatedTransitioning 프로토콜을 준수하여 애니메이션과 듀레이션을 정의해주어야 한다.

동작 방식을 살펴보자

/// 실제 코드는 레이웬더리치 블로그에

import UIKit

class AnimationController: NSObject, UIViewControllerAnimatedTransitioning {
  
  // start point for animation
  private let originFrame: CGRect
  
  // 시작할 프레임을 가져와서 스냅샷을 만들기 위해 필요
  init(originFrame: CGRect) {
    self.originFrame = originFrame
  }
  
  // 애니메이션 동작시간
  func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
    return 1
  }
  
  func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
    /* 1 - 다음 필요한 항목들을 가져온다.
    	1. fromView와 toView를 context
        2. fromView와 toView사이에 보여질 snapshot
        3. transition에서 보여질 containerView
        4. toView가 마지막으로 보여질 finalFrame
    */
    
    /* 2 - 애니메이션 전처리를 해준다.
    	1. containerView에는 fromView만 들어가있으므로 toView와 snapshot을 추가
        2. toView를 숨김처리
        3. 애니메이션 설정
        4. 듀레이션 설정
    */
    
    /* 3 - 애니메이션을 처리해준다.
    	1. 시작프레임과 끝프레임, 시간, completion등을 처리
    */
  }
}

2) 뷰 컨트롤러에 델레게이트 설정

A 뷰컨에서 B뷰컨으로 transition할 경우,
A 뷰컨에 UIViewControllerTransitioningDelegate을 채택해주고,
B 뷰컨의 transitioningDelegate를 A 뷰컨으로 설정해주어야한다.

다음과 같이 설정하면 된다.

import UIKit

class CardViewController: UIViewController {
  
  static let cardCornerRadius: CGFloat = 25
  
  // UI 그리고 세팅
  
  // destination으로 갈때 destination의 delegate를 self로
  override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segueIdentifier(for: segue) == .reveal,
      let destinationViewController = segue.destination as? RevealViewController {
      destinationViewController.transitioningDelegate = self
    }
}

// Animation 처리를 담당할 클래스, Dismiss를 담당할 클래스를 각각 정의해준다.
extension CardViewController: UIViewControllerTransitioningDelegate {
  func animationController(
    forPresented presented: UIViewController, 
    presenting: UIViewController, 
    source: UIViewController
  ) -> UIViewControllerAnimatedTransitioning? {
    return FlipPresentAnimationController(originFrame: cardView.frame)
  }
  
  func animationController(
    forDismissed dismissed: UIViewController
  ) -> UIViewControllerAnimatedTransitioning? {
    guard let _ = dismissed as? RevealViewController else {
      return nil
    }
    
    return FlipDismissAnimationController(destinationFrame: cardView.frame)
  }
}

이렇게 할 경우 다음과 같은 애니메이션을 볼 수 있다.

profile
iOS Developer

0개의 댓글