์ด์ ๊ธ์์ PresentationController๊ฐ ๋ฌด์์ธ์ง ๋ฐฐ์ ๋ค. ๊ทธ๋ฐ๋ฐ, Transition Animator๋ฅผ ์ ๊ณตํ๋ ๋ถ๋ถ์์ UIViewControllerAnimatedTransitioning
์ด๋ผ๋ ์น๊ตฌ๋ฅผ ๋ณด์๋ค. ์ค๋์ ์ฃผ์ ๋ ์ด๋
์์ด๋ค.
UIViewControllerAnimatedTransitioning
Custom Transition์ ์์ด ํ์ํ animation์ ๊ตฌํํ๊ธฐ ์ํ method๋ค์ด ๋ชจ์ฌ ์๋ ํ๋กํ ์ฝ์ด๋ค. ์ด ํ๋กํ ์ฝ์ ์ฑํํ ๊ตฌํ์ฒด๋ฅผ ๋๊ฒจ์ฃผ๋ฉด ๋๋ค.
ํด๋น Protocol์ method๋ฅผ ์ฌ์ฉํ๋ฉด, โ๊ณ ์ ๋ ์๊ฐ ๋ด์ VC๋ฅผ ํ๋ฉด๋ฐ์ผ๋ก ์ ํํ๊ธฐ ์ํ ์ ๋๋ฉ์ด์
์ ์ ์ํ ๊ฐ์ฒดโ๋ฅผ ๋ง๋ค ์ ์๋ค. ๋ํํ ๊ฐ์ ๊ฒฝ์ฐ UIViewControllerInteractiveTransitioning
๋ฅผ ํตํด ์ฒ๋ฆฌํด์ฃผ์ด์ผ ํ๋ค. ๊ตฌํํด์ผ ํ๋ method๋ค์ ๋ค์๊ณผ ๊ฐ์ ๊ฒ๋ค์ด ์๋ค.
transitionDuration(using:)
: Required- Transition Animation์ Duration์ ์ง์ ํ๋ค.
animateTransition(using:)
: Required- animation์ ์ ์ํด์ค๋ค.
- ์ํฉ์ ๋ง๋ ์ฌ๋ฌ ๋ค๋ฅธ animator๋ฅผ ์ ๊ณตํ ์๋ ์๋ค. (์๋ฅผ ๋ค์ด
.present
,.dismiss
)
๋ Method ๋ชจ๋ UIViewControllerContextTransitioning์ด๋ผ๋ Protocol ๊ตฌํ์ฒด๋ก๋ถํฐ Transition์ด ์ผ์ด๋๋ ๋์์ ์ ๋ณด๋ค์ ์ป์ ์ ์๋ค. ์ด๋ฅผ Transition Context๋ผ ํ๋ค. ๊ทธ ์์๋ ์ด์ ๊ธ์์ ์ค๋ช
ํ containerView
, Frame
์ ๋ณด, isInteractive
, isAnimated
๋ฑ๋ฑ์ ์ ๋ณด๋ฅผ ์ป์ ์ ์๋ค.
Project
์ด์ ์ ๋ณด์๋ AppStore์ ์ฐ์ฅ์ ์์ ์์๋ณด๊ฒ ๋ค. ์ด์ ์ CardDetailViewController
๊ฐ UIViewControllerTransitioningDelegate
๋ฅผ ์ฑํํ๊ณ ์ฌ๊ธฐ์ 3๊ฐ์ method๋ฅผ ๊ตฌํํด์คฌ์๋๋ฐ, Presentation Controller์ ๊ด๊ณ ์๋ ๋ฉ์๋๊ฐ ๋ ์์๋ค.
extension CardDetailViewController: UIViewControllerTransitioningDelegate {
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return TodayAnimationTransition(animationType: .present)
}
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return TodayAnimationTransition(animationType: .dismiss)
}
func presentationController(forPresented presented: UIViewController, presenting: UIViewController?, source: UIViewController) -> UIPresentationController? {
return CardPresentationController(presentedViewController: presented, presenting: presenting)
}
}
์์ ๋ ๋ฉ์๋๊ฐ ๊ทธ๊ฒ์ด๋ค. ์ด์ ๊ธ์์๋ present, dismiss์ ๋ง๋ ๊ฐ๊ฐ์ animator๋ฅผ ์ ๊ณตํด์ฃผ์๋ค๊ณ ํ์๋ค. ์ด์ ๋ ์ ๋ ์์ ์ค์ฒด๋ฅผ ํ์ธํ ์ฐจ๋ก์ด๋ค.
TodayAnimationTransition
fileprivate let transitonDuration: TimeInterval = 1.0
enum AnimationType {
case present
case dismiss
}
class TodayAnimationTransition: NSObject {
let animationType: AnimationType!
init(animationType: AnimationType) {
self.animationType = animationType
super.init()
}
}
์ผ๋จ ๊ธฐ๋ณธ ๋ฐ์ฐฌ๋ถํฐ ๋ณด์. animator์ ๊ด๋ จ๋ ๊ฒ์ ์ฒ๋ฆฌํ๊ธฐ ์ํด์ time interval์ ์ ์ํ์๊ณ , Type๊น์ง ๋๋ ์ ๊ด๋ฆฌํ๊ณ ์๋ค. ์ด๊ธฐํํ ๋, Type์ ์ ์ํ๋ฉด, ์ด์ ๋ง๋ Animator๋ฅผ ์ ๊ณตํ ์๊ฐ์ธ๊ฐ๋ณด๋ค.
extension TodayAnimationTransition: UIViewControllerAnimatedTransitioning {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return transitonDuration
}
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
if animationType == .present {
animationForPresent(using: transitionContext)
} else {
animationForDismiss(using: transitionContext)
}
}
}
์๊น ๋งํ๋ UIViewControllerAnimatedTransitioning
๋ฅผ ๊ตฌํํ ๋ Required๋๋ ๋๊ฐ์ method๋ฅผ ๊ตฌํํ๊ณ ์๋ค. animation ์ง์ ์๊ฐ๊ณผ, ์ด๋ค animation์ ์งํํ ๊ฒ์ธ์ง์ ๋ํ method์ด๋ค. ์ฝ๋ ์์ฑ์๋ type์ ๋ง๊ฒ ๋๊ฐ์ ์ฒ๋ฆฌ๋ฅผ ํ๊ณ ์๋ค.
extension TodayAnimationTransition: UIViewControllerAnimatedTransitioning {
func animationForPresent(using transitionContext: UIViewControllerContextTransitioning) {
let containerView = transitionContext.containerView
//1.Get fromVC and toVC
guard let fromVC = transitionContext.viewController(forKey: .from) as? UITabBarController else { return }
guard let tableViewController = fromVC.viewControllers?.first as? TodayViewController else { return }
guard let toVC = transitionContext.viewController(forKey: .to) as? CardDetailViewController else { return }
guard let selectedCell = tableViewController.selectedCell else { return }
let frame = selectedCell.convert(selectedCell.bgBackView.frame, to: fromVC.view)
//2.Set presentation original size.
toVC.view.frame = frame
toVC.scrollView.imageView.frame.size.width = GlobalConstants.todayCardSize.width
toVC.scrollView.imageView.frame.size.height = GlobalConstants.todayCardSize.height
containerView.addSubview(toVC.view)
//3.Change original size to final size with animation.
UIView.animate(withDuration: transitonDuration, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0, options: [], animations: {
toVC.view.frame = UIScreen.main.bounds
toVC.scrollView.imageView.frame.size.width = kScreenW
toVC.scrollView.imageView.frame.size.height = GlobalConstants.cardDetailTopImageH
toVC.closeBtn.alpha = 1
fromVC.tabBar.frame.origin.y = kScreenH
}) { (completed) in
transitionContext.completeTransition(completed)
}
}
func animationForDismiss(using transitionContext: UIViewControllerContextTransitioning) {
guard let fromVC = transitionContext.viewController(forKey: .from) as? CardDetailViewController else { return }
guard let toVC = transitionContext.viewController(forKey: .to) as? UITabBarController else { return }
guard let tableViewController = toVC.viewControllers?.first as? TodayViewController else { return }
guard let selectedCell = tableViewController.selectedCell else { return }
UIView.animate(withDuration: transitonDuration - 0.3, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0, options: [], animations: {
let frame = selectedCell.convert(selectedCell.bgBackView.frame, to: toVC.view)
fromVC.view.frame = frame
fromVC.view.layer.cornerRadius = GlobalConstants.toDayCardCornerRadius
fromVC.scrollView.imageView.frame.size.width = GlobalConstants.todayCardSize.width
fromVC.scrollView.imageView.frame.size.height = GlobalConstants.todayCardSize.height
fromVC.closeBtn.alpha = 0
toVC.tabBar.frame.origin.y = kScreenH - toVC.tabBar.frame.height
}) { (completed) in
transitionContext.completeTransition(completed)
toVC.view.addSubview(toVC.tabBar)
}
}
}
์ค์ ์งํํ๋ code๊ฐ ์ฌ๊ธฐ์ ๋ด๊ฒจ์๋ค. ์ฌ์ค ์ด ๋ถ๋ถ์ ๋์ค์ ๊ตฌํํ๋ฉด์ ์ฝ์งํ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ๋ ์ค์ํ๋ค๊ณ ํ๋จํ์ฌ ์คํตํ๋ค.
Reference
- UIViewControllerAnimatedTransitioning
- UIViewControllerInteractiveTransitioning
- UIViewControllerContextTransitioning
- iOS) UIPresentationController ๋ฅผ ์์๋ณด๊ณ App Store clone app ์ ์ดํด๋ณด์
- iOS) Presentation ๊ณผ Transition ๊ทธ๋ฆฌ๊ณ Animationโฆ
- iOS Swift Tutorial: Create Advanced Interactive Animations with UIKit
- appstore-clone