์ ๋ฌธํ์ง ์ผ๋ง ๋์ง ์์ ๋๋ ์ฌ์ ํ ๊ธฐ๋ณธ Transition๋ง ์ฌ์ฉํ๊ณ ์๋ค. ๋๋ ํ๋ คํ UX๋ฅผ ๋ง๋ค์ด๋ณด๊ณ ์ถ๋ค! ๊ทธ ์ ์, ๊ทธ ์์์ด ๋๋ UIPresentationController๋ถํฐ ์์๋ณด์.
์์์ ์์
๊ทธ ์ ์, ์ฌ์ค Presentation๊ณผ Transition์ด ๋ญ์ง๋ ์ ๋ชจ๋ฅด๊ฒ ๋ค. ์ผ๋จ์ ์์ ๊ฐ์ ๊ทธ๋ฆผ์ ๋ง์์์ ์ด์ง๋ง ๋ฃ์ด๋์. ์ ํํ ๊ทธ๋ฆผ์ ์๋๋ค. ๋ค๋ง Presentation์ด๋ผ๋ ๊ฐ๋ ์ด Transition์ ํฌํจํ๋, ๊ฐ์ธ๋ ์์ ๊ฐ๋ ์ฒ๋ผ ๋์ํ๋ค๋ ์ ์ ๊ธฐ์ตํ์. ๊ทธ๋ฆฌ๊ณ Animation์ ์ค์ animation ๊ด๋ จ ์ฝ๋๊ฐ ๋ค์ด๊ฐ๋ ๋ถ๋ถ์ด๋ค. ํด๋น ๋ถ๋ถ์ ์ด๋ ๊ณณ(presentation, transition)์์๋ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค. ๋ค๋ง ์ค์ ๋์์ ๊ธฐ์ ํ๋ ๊ณณ์ด๋ผ ์๊ฐํด๋์.
UIPresentationController
์ผ๋จ ๊ฐ๋ ๋ถํฐ ์ก๊ณ ๊ฐ์ผํ๋ค. ํ๋ฉด ์ ํ์ ํ๊ณ ์ถ์๋ฐ, ๋๋ผ๋ฉด ์ด๋ค์์ผ๋ก ๋ง๋ค์ด์ ๊ด๋ฆฌํ ๊น? ํ๋ฉด์ ์ ํ์ ์์ด์ ๋ฌด์์ด ํ์ํ ์ง ํ๋ฒ ์๊ฐํด๋ณด์.
์ผ๋จ ํ๋ฉด ์ ํ์ ํธ์ถํ๋ VC, ๊ทธ๋ฆฌ๊ณ ์ค์ ๋ก ๋ค์์ ๋ณด์ฌ์ง VC ๋ ๋
์์ด ํ์ํ ๊ฒ์ด๋ค. ๊ทธ๋ฆฌ๊ณ ์ด ๋ VC๋ค์ด ์ ์๋๋ง Transition์ด ์ผ์ด๋๋ฉด์ ๋ชธ๋ด๊ณ ์์ View๊ฐ์ ๊ฒ๋ ํ์ํ ๊ฒ์ด๋ค. ์ค์ ๋ก ์ด๋ฌํ ๊ฒ๋ค์ ๊ด๋ฆฌํด์ฃผ๋ ๋
์์ด ๋ฐ๋ก UIPresentationController
์ด๋ค.
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.presentingViewController // == self.presentationViewController.presentingViewController
self.presentedViewController // == self.presentationViewController.presentedViewController
}
}
viewController instance์ ์ ๊ทผํ๋ฉด presentingViewController
์ด์น๊ตฌ์ presentedViewController
์ด์น๊ตฌ๋ฅผ ๋ณผ ์ ์๋๋ฐ, ๋ฐ๋ก presentationViewController
์ฌ๊ธฐ์ ์ค๋ computed property์ด๋ค.
์ด๋
์์ ๋ชจ๋ ViewController๊ฐ ๊ฐ์ง๊ณ ์์ผ๋ฉฐ, ViewController๊ฐ ๋ณด์ฌ์ง ์์ ์์ ์ข
๋ฃ๋ ๋๊น์ง ์ด ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ Presentation ๊ด๋ จ Process๋ฅผ ์ฒ๋ฆฌํ๋ค. ์ฐ๋ฆฌ๊ฐ ViewController์์ ์
๋ ฅํ๋ modalPresentationStyle
, modalTransitionStyle
์ Built-in ๋ ๊ธฐ๋ฅ์ผ๋ก, ๊ฒฐ๊ตญ์๋ UIPresentationViewController
๊ฐ ์ฒ๋ฆฌํ๋ ๊ฒ์ด๋ค.
๊ฐ๋จํ Transition์ ๋ณํ๊ฐ์ ๊ฒฝ์ฐ์๋ ViewController instance์ modalPresentationStyle
, modalTransitionStyle
๋ง์ ๋ณ๊ฒฝํ๋ ๊ฒ์ผ๋ก ์ ์ฉ์ด ๊ฐ๋ฅํ๋ค. ๋ณต์กํ Transition์ ์ ์ฉํ๊ณ ์ถ์ ๊ฒฝ์ฐ์๋ UIModalPresentationStyle.custom
์ผ๋ก modalPresentationStyle
๋ฅผ ๋ณ๊ฒฝํด์ฃผ์ด์ผ ํ๋ค. ๋ณ๊ฒฝํ ํ์๋ Transition์ด ์ผ์ด๋๋ Background view์ ๊ฐ์ ์์ฑ๋ค์ ๋ณ๊ฒฝํ ์ ์๋ค.
ํน์ ViewController์์ ์ด๋ฐ ์์ฑ์ ์ ์ฉํ๊ณ ์ถ์ผ๋ฉด, UIViewControllerTransitioningDelegate
๋ฅผ ์ฑํํ์ฌ ์ ๊ณตํ ์ ์๋ค. ์ด๋ค PresentationViewController๋ฅผ ์ฌ์ฉํ ๊ฒ์ธ์ง, Transition์์ ์ฌ์ฉํ๋ Animator๋ ์ด๋ค ๊ฒ์ ์ฌ์ฉํ ๊ฒ์ธ์ง, interactive animator๋ฅผ ์ฌ์ฉํ ๊ฑฐ๋ผ๋ฉด ์ด๋ค ๊ฒ์ธ์ง๋ฅผ ๋ฌป๊ฒ ๋๋ค. ์ฌ๊ธฐ์ interactive animator๊ฐ ๋ญ์ง ๋ชฐ๋๋๋ฐ, ํด๋น ์์์ ํ๋ฐ๋ถ๋ฅผ ๋ณด๋ฉด ๋ญ์ง ์ ์ ์๋ค. ์์ฝํด์ ๋งํ๋ฉด push๊ฐ ์ผ์ด๋๋๋ฐ ์ด๊ฑธ ์๊ฐ๋ฝ์ผ๋ก ์๋ฆฌ๊ฐ๋ฆฌ ์น ์ ์๋ ๊ฑธ ๋งํ๋ค. ๊ทธ๊ฒ ์๋๋ ๊ฑด ๋๋ฅด๋ฉด ๊ทธ๋ฅ ์ ๋๋งค์ด์
์ด ์๋ํ๋ ๊ฒ์ด๋ค.
Presentation Context, Frame
์ฌ๊ธฐ์ ์ ๊น ์ด ๊ฐ๋ ์ ์๊ณ ๊ฐ์. ๋ฌธ์๋ฅผ ์ฝ๋ค๋ณด๋ฉด Context๋ผ๋ ๋จ์ด๊ฐ ์ข ์ข ๋์จ๋ค. ์ด๊ฑด Built-In ๊ธฐ๋ฅ์ ๋ง๋ค๊ฒ ๋๋ฉด์ ๋ฐ์ํ ๋จ์ด๋ก ๋ณด์ธ๋ค.
๋ด๊ฐ Apple UIKit ๊ฐ๋ฐ์๋ค. ์ด๋ป๊ฒ๋ ์ฝ๊ฒ ์ฌ์ฉํ๊ฒ ๋ง๋ค๊ธฐ ์ํด์, ๊ธฐ๋ณธ์ ์ผ๋ก ๋ง์ด ์ฌ์ฉํ๋ show(navigationController push)์ present(modal)์ ๋ง๋ค์๋ค. ๊ทธ๋ฐ๋ฐ ์ด show๋ผ๋ ๋ฉ์๋๋ฅผ ์ฌ์ฉ์๊ฐ ์๋ชป ์ฌ์ฉํ๋ค. ์ฆ, navigationController์์ ๋์ํ๋ผ๊ณ ๋ง๋ค์ด๋จ๋๋, ๋๊ฐ์ด ์ด๋ณด์๊ฐ ๊ทธ๋ฅ ์จ๋ฒ๋ ธ๋ค. ์ด๋ด ๊ฒฝ์ฐ์ ์ด๋ป๊ฒ ๋์ํ๊ฒ ๋ง๋ค๊น?
์ด๋ฌํ ์ํฉ์์ Apple ๊ฐ๋ฐ์๋ค์, ํ์ฌ presentation context, ์ฆ ์ํฉ์ ๋ง์ถฐ์ ๋์ํ๋ ๊ฐ๋ ์ ๋ง๋ค์๋ค. ๋ง์ฝ ํ์ฌ show๊ฐ ์คํ๋ ViewController๊ฐ NavigationController๋ฅผ Container Controller๋ก ๊ฐ์ง๊ณ ์๋ค๋ฉด, push ๋์์ ํ ๊ฒ์ด๋ค. ๋จ์ผ ViewController์๋ค๋ฉด present ๋์์ ํ ๊ฒ์ด๋ค. ์ฌ๊ธฐ์ ํ์ฌ ๋ฌธ๋งฅ์ ๋งํ๋ ๊ฒ์ presentation context๋ผ ํ๋ค. ๊ทธ๋ฆฌ๊ณ presentation context๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ํ์ฌ presentating controller(๋ณด์ฌ์ฃผ๋ ค๊ณ ํ๋ VC)๋ฅผ Frame์ด๋ผ ํ๋ค.
containerView
Transition์ด ์ผ์ด๋๋ฉด์ ViewController๊ฐ ์ํด์๋ ๊ณณ์ด๋ค. UIKit์ transitioning delegate๋ฅผ ์ ๊ณต๋ฐ์ ๋ค์ ํด๋น property๋ฅผ ์ด๊ธฐํํ๋ค. ๊ธฐ๋ณธ์ ์ผ๋ก presented viewController์ view์ ์กฐ์์ด๋ค. ๋ํ transition animation์ด ์งํ๋ ๋๋ presenting view๊น์ง container view์ ์ถ๊ฐํ๋ค.
animator๊น์ง custom์ผ๋ก ๋ง๋ค์ด์ ์ฒ๋ฆฌํ๋ ๊ฒฝ์ฐ์ ์ด animator ๊ฐ์ฒด๋ค์ container view๋ฅผ containerView
property๋ก ์ ๊ทผํด์ ์ฌ์ฉ์ด ๊ฐ๋ฅํ๋ค๊ณ ํ๋ค.
์ ๋ฆฌ
์ด์ฏค ์ฝ์ผ๋ฉด ์ Presentation์ด ๊ฐ์ธ๋ ๊ฐ๋
์ด๋ผ๊ณ ํ๋์ง ์ดํด๊ฐ ๋ ์ง๋ ๋ชจ๋ฅด๊ฒ ๋ค. ์ผ๋จ ๋๋ ๊ทธ๋ ๊ฒ ์๊ฐํ๊ณ ์๋ค. ์ค์ ๋ก ์ฝ๋๋ฅผ ๋ณด๋ฉด ๊ฐ์ UIViewControllerTransitioningDelegate
์์ ์ ๊ณตํ๊ณ ์๊ธด ํ์ง๋ง, ์ด๊ฒ์ด ๋ณด๋ค ๊ฐ๋
์ ์ผ๋ก ์ดํด๊ฐ ์ฌ์ ๋ค.
transition animator๋ ์ ๊ณตํ๋ค๊ณ ํ๋๋ฐ, ์ด ๋, present๋ ๋์ animator์ dismissal๋ ๋ animator ๋๊ฐ๋ฅผ ์ ๊ณตํด์ฃผ์ด์ผ ํ๋ค.
Presentation Process
์ด์ ์ด๋ค ์์๋ก Presentation์ด ์ผ์ด๋๋์ง ์์๋ณด์.
- Presentation
- Transition Animation์ ์ฐ์ํ ๊ฒ๋ค์ด ์คํฌ๋ฆฐ์ ํํ๋์ด ์ VC๋ฅผ ๋ณด์ฌ์ฃผ๋ ๊ณผ์ ์ ๋งํ๋ค.
- Management
- ํ๋ฉด ํ์ ๋ฑ์ ๊ด๋ จ๋์ด Animation์ด ๋์ด์ผ ํ๋ ๊ฒ์ ์ฒ๋ฆฌํ๋ค.
- Dismissal
- Transition Animation์ ์ฐ์ํ ๊ฒ๋ค์ด ์คํฌ๋ฆฐ์ ํํ๋์ด ์ด์ VC๋ฅผ ๋ณด์ฌ์ฃผ๋ ๊ณผ์ ์ ๋งํ๋ค.
์ฐจ๋ก๋๋ก ๊ฐ๊ฐ ์์๋ณด์.
Presentation
- ViewController๊ฐ ์๋ก์ด ํ๋ฉด์ ์์ฒญํ๋ค.
- TransitioningDelegate์๊ฒ ์ด๋ค PresentationController๋ฅผ ์ฌ์ฉํ ๊ฑด์ง ๋ฌผ์ด๋ณธ๋ค. ()
- Delegate๊ฐ ์ ์๋ PresentationController๋ฅผ ๋ง๋ค์ด์ ๋๊ธด๋ค.
- PresentationController๋ Custom Presentation์ ์คํํ๋ค.
presentationTransitionWillBegin()
๋ฉ์๋๊ฐ ์คํ๋๋ค.- Transition์์ ์ฌ์ฉ๋๋ CustomView๋ฅผ ์ถ๊ฐํ๋ค.
- Animation์ ํ์ํ ๋ค๋ฅธ ์์ฑ๋ค์ ์ค์ ํ๋ค.
- Transition์ด ์ค์ ๋ก ์งํ๋๋ฉด์ ํ๋ฉด์ด ์ ํ๋๋ค.
- ์คํ๋๋ ๋์
containerViewWillLayoutSubviews()
,containerViewDidLayoutSubviews()
๊ฐ ํธ์ถ๋๋ค. - ํด๋น ๋ฉ์๋๋ฅผ overrideํ์ฌ presentation controller์์ ์ฌ์ฉํ๋ custom view๋ฅผ updateํ ์ ์๋ค.
- ์คํ๋๋ ๋์
- Transition์ด ์๋ฃ๋๋ฉด
presentationTransitionDidEnd()
๋ฉ์๋๊ฐ ์คํ๋๋ค.
์ค์ ๋ก ๊ทธ๋ฌํ์ง ์๋ฌธ์ค๋ฌ์ ํ ์คํธ ํ๋ค.
presentationTransitionWillBegin Called!!!
containerViewWillLayoutSubviews Called!!!
containerViewDidLayoutSubviews Called!!!
presentationTransitionDidEnd Called!!!
์ค์ ๋ก ๊ทธ๋ฌ๋ค!
Management
๋ค์์ผ๋ก๋ Management์ด๋ค. ํ๋ฉด ํ์ ๋ฑ์ ์ฒ๋ฆฌํ๋๋ฐ, size์ ๋ณํ๊ฐ ์ผ์ด๋ ๊ฒฝ์ฐ viewWillTransition(to:with:)
๋ฅผ ํธ์ถํ๋ค. ์ด๊ฒ ์ด ์น๊ตฌ์ ๊ด๋ จ๋์ง ์ฒ์ ์์๋ค. autoLayout์ ์ฌ์ฉํ๊ณ ์๋ค๋ฉด ํฌ๊ฒ ํด์ค ์์
์ ์๋ค.
Dismissal
- Presented View Controller๋ฅผ ๋ซ์์ ์์ฒญํ๋ค.
dismissalTransitionWillBegin()
๋ฉ์๋๊ฐ ํธ์ถ๋๋ค.- Dismissal์ด ์งํ๋๋ค.
- Dismissal transition์ด ๋๋๋ฉด
dismissalTransitionDidEnd()
์ด ํธ์ถ๋๋ค.
Project
์ด ๊ฐ๋ ์ ์ด๋ป๊ฒ ์ฝ๋๋ก ํํํ ์ง ํ๋ค๊ฐ ์ข์ Repo๋ฅผ ๋ฐ๊ฒฌํ๋ค. App store๊ฐ ์๋นํ ๊น๋ํ transition์ ์ ๊ณตํ์๋๋ฐ, ์ด๋ฅผ Cloneํ ์ฌ๋์ด ์๋๋ผ.. ๋ก์ผ
๋ชจ๋ ํ๋ฉด์ ๋ณผ ๊ฑด ์๋๊ณ , ๋ฑ ์ด Transition customํ ๋ถ๋ถ๋ง ๋ณด๋ ค๊ณ ํ๋ค. ๋ฐ๋ก ์ด๋ถ๋ถ.
Transition์ CardDetailViewController โ TodayViewController๋ก ๋ฐ์ํ ๊ฑฐ๋ค. ์ฌ์ค์ Presenting ViewController์์ ๋ง์ ์์ ์ ํ ๊ฑฐ๋ค. ์ฆ, CardDetailViewController์์ PresentationViewController๋ฅผ ๋ฃ์ด์ค ๊ฑฐ๋ค. ํ๋์ฉ ๋ณด์.
CardDetailViewController
์, ๋จผ์ Presenting View Controller, ์ฆ ์ฌ๊ธฐ์๋ Card์ Detail์ ๋ณด์ฌ์ฃผ๋ ์ด ์น๊ตฌ๋ก ๋ถํฐ transition์ด ์์๋๊ธฐ ๋๋ฌธ์ CardDetailViewController ์๊ฐ Presenting View Controller์ด๋ค. ์ฌ๊ธฐ์ moodalPresentationStyle = .custom
์ผ๋ก ๋ฐ๊ฟ์ฃผ๊ณ ์์ํด์ผ ํ๋ค!!
class CardDetailViewController: UIViewController {
init(cell: TodayTableViewCell) {
self.cell = cell
super.init(nibName: nil, bundle: nil)
self.setupTranstion()
}
private func setupTranstion() {
modalPresentationStyle = .custom
transitioningDelegate = self
}
}
๊ทธ๋ฆฌ๊ณ ๋์ ์ด์ ์ง์ง ํต์ฌ ๋ถ๋ถ์ ํ์ธํด๋ณด์.
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)
}
}
ํต์ฌ์ ์ด๋ถ๋ถ์ด๋ค. ๋๋ ์ ๋ ์ด๋ค PresentationViewController๋ฅผ ์ ๊ณตํ ๊ฒ์ธ์ง, ์ด๋ค Animator๋ฅผ ์ ๊ณตํ ๊ฒ์ธ์ง๋ฅผ ์ ์ํด์ฃผ๋ฉด ๋๋ค. ์ฌ๊ธฐ์๋ interaction์ด ํ์์์ผ๋ฏ๋ก transition animator๋ง ์ ์ฉํ ๊ฒ์ ๋ณผ ์ ์๋ค. presentํ ๋์ dismissํ ๋ ๋ ๊ฐ์ animator๋ฅผ ์ ๊ณตํ๋ค.
CardPresentationController
๊ทธ๋ฌ๋ฉด ์ด์ PresentationViewController๋ฅผ ์ด๋ป๊ฒ ๋ง๋๋์ง๋ง ์๋ฉด ๋๋ค.
class CardPresentationController: UIPresentationController {
private lazy var blurView = UIVisualEffectView(effect: nil)
}
์ผ๋จ ์ด๋ ์์ ์ถํ PresentationViewController์ containerView์ ๋ค์ด๊ฐ ๋ ์์ด๋ค. ์ค์ ๋ก ์ฑ์คํ ์ด ์ด์ด์ ๋๋ฅด๋ฉด ๋ค์ View์ ๋ค๋ฅธ View๋ก ๊ฐ์ธ์ง๋ฉด์ ๋ณด์ธ๋ค. ๊ทธ๋์ ๋ญ๊ฐ ๊น๋ํด๋ณด์ด๋ ๊ฑฐ๋ค. ๊ทธ Blur๋ฅผ ๋ด๋นํ๋ ์น๊ตฌ๋ค.
class CardPresentationController: UIPresentationController {
override var shouldRemovePresentersView: Bool {
return false
}
}
๊ทธ ๋ค์์ผ๋ก๋ ์ด์น๊ตฌ๋ค. ์๋ ์ด์ Animation์ด ๋๋ ํ์ ๋ค์ ๋ฐฐ๊ฒฝ View๋ฅผ ๋ฉ๋ชจ๋ฆฌ์์ ๋ ๋ฆด ๊ฑด์ง ๋ฌผ์ด๋ณด๋ ๊ฐ์ด๋ค. ๊ธฐ๋ณธ๊ฐ์ false๋ก ๋์ด ์๋ค. ๊ทผ๋ฐ ์ ๊ตณ์ด ์ ์๋์ง๋ ๋ชจ๋ฅด๊ฒ ๋ค. ๋ง์ฝ ๋ท ๋ฐฐ๊ฒฝ์ด ๊ณ์ํด์ ํ์ํ๋ค๋ฉด, ์๋ฅผ ๋ค์ด VC๊ฐ full view๋ก ์๋ณด์ธ๋ค๋ฉด ์๋ฏธ์๋ ๊ฐ์ผ ์ ์๊ฒ ๋ค.
class CardPresentationController: UIPresentationController {
override func presentationTransitionWillBegin() {
let container = containerView!
blurView.translatesAutoresizingMaskIntoConstraints = false
container.addSubview(blurView)
blurView.edges(to: container)
blurView.alpha = 0.0
presentingViewController.beginAppearanceTransition(false, animated: false)
presentedViewController.transitionCoordinator!.animate(alongsideTransition: { (ctx) in
self.blurView.effect = UIBlurEffect(style: .light)
self.blurView.alpha = 1
}) { (ctx) in }
}
override func presentationTransitionDidEnd(_ completed: Bool) {
presentingViewController.endAppearanceTransition()
}
override func dismissalTransitionWillBegin() {
presentingViewController.beginAppearanceTransition(true, animated: true)
presentedViewController.transitionCoordinator!.animate(alongsideTransition: { (ctx) in
self.blurView.alpha = 0.0
}, completion: nil)
}
override func dismissalTransitionDidEnd(_ completed: Bool) {
presentingViewController.endAppearanceTransition()
if completed {
blurView.removeFromSuperview()
}
}
}
์ด์ ๋ณธ๊ฒฉ์ ์ผ๋ก life cycle๊ณผ ๊ด๋ จ๋ ๋
์๋ค์ด ๋์จ๋ค. ํด๋น ์ฝ๋๋ฅผ ๋ณด๋ฉด transition์ด ์ผ์ด๋๊ธฐ ์ ์ ํ์ํ ์์๋ค์ ์ฌ๊ธฐ์ ์ธํ
ํ๊ณ ์์์ ๋ณผ ์ ์๋ค. ์ ๊ธฐ ๋ณด์ด๋ animate(alongsideTransition)
์ animation์ ๋์์ ์คํ์ํค๋ method์ด๋ค.
Reference
- UIPresentationController
- UIViewControllerTransitioningDelegate
- UIViewControllerAnimatedTransitioning
- modalPresentationStyle
- UIModalPresentationStyle
- containerViewWillLayoutSubviews()
- containerViewDidLayoutSubviews()
- shouldRemovePresentersView
- iOS) UIPresentationController ๋ฅผ ์์๋ณด๊ณ App Store clone app ์ ์ดํด๋ณด์
- iOS) Presentation ๊ณผ Transition ๊ทธ๋ฆฌ๊ณ Animationโฆ
- iOS Swift Tutorial: Create Advanced Interactive Animations with UIKit
- appstore-clone