@@ -48,10 +48,14 @@ extension CollectionViewCellTransitioning: UIViewControllerAnimatedTransitioning
4848 transitionDuration
4949 }
5050
51+ /// 실제 Transition 구현 부분
5152 func animateTransition( using transitionContext: any UIViewControllerContextTransitioning ) {
53+ /// 전환에 관련된 뷰를 사용합니다.
5254 let containerView = transitionContext. containerView
55+ /// 1. 깔끔한 애니메이션을 위해 transition되는 containerView의 모든 요소를 제거합니다.
5356 containerView. subviews. forEach { $0. removeFromSuperview ( ) }
5457
58+ /// 2. 전환에 사용되는 뷰에 blurEffectView 추가합니다.
5559 blurEffectView. frame = containerView. frame
5660 blurEffectView. alpha = transition. next. blurAlpha
5761 containerView. addSubview ( blurEffectView)
@@ -60,45 +64,61 @@ extension CollectionViewCellTransitioning: UIViewControllerAnimatedTransitioning
6064 let toView = transitionContext. viewController ( forKey: . to)
6165
6266 var thumbnailView : ThumbnailView ?
67+ /// 3. Present: 시작하는 뷰의 썸네일을 가져옵니다. (시작 좌표 및 복사를 위해)
6368 if let navigationController = ( fromView as? UINavigationController ) , let viewController = ( navigationController. topViewController as? BroadcastCollectionViewController ) {
6469 thumbnailView = viewController. selectedThumbnailView
6570 }
6671
72+ /// 3. Dismiss: 목적지 뷰의 썸네일을 가져옵니다. (도착 좌표 및 복사를 위해)
6773 if let navigationController = ( toView as? UINavigationController ) , let viewController = ( navigationController. topViewController as? BroadcastCollectionViewController ) {
6874 thumbnailView = viewController. selectedThumbnailView
6975 }
7076
77+ /// 4. 썸네일 뷰를 복사하고 절대 프레임을 가져옵니다.
7178 guard let thumbnailView else { return }
7279 let thumbnailViewCopy = copy ( of: thumbnailView)
73- containerView. addSubview ( thumbnailViewCopy)
74- thumbnailView. isHidden = true
75-
7680 let absoluteFrame = thumbnailView. convert ( thumbnailView. frame, to: nil )
77- thumbnailViewCopy. frame = absoluteFrame
78- thumbnailViewCopy. layoutIfNeeded ( )
7981
80- backgroundView. frame = transition == . present ? thumbnailViewCopy. imageView. frame : containerView. frame
82+ /// 애니메이션의 디테일을 위한 설정
83+ backgroundView. frame = transition == . present ? absoluteFrame : containerView. frame
8184 backgroundView. layer. cornerRadius = transition. cornerRadius
8285 thumbnailViewCopy. insertSubview ( backgroundView, aboveSubview: thumbnailViewCopy. shadowView)
8386
87+ /// 5. 기존 썸네일을 숨기고 복사한 썸네일을 containerView에 추가합니다.
88+ containerView. addSubview ( thumbnailViewCopy)
89+ thumbnailView. isHidden = true
90+
91+ /// 6. Present: 애니메이션, 작았다 커지면서 위로 이동합니다.
8492 if transition == . present, let toView {
93+ /// 6-1. 썸네일은 원래 위치에서 시작
94+ thumbnailViewCopy. frame = absoluteFrame
95+ /// 6-2. containerView에 띄워줄 뷰 추가 후 숨김
8596 containerView. addSubview ( toView. view)
8697 toView. view. isHidden = true
98+ /// 6-3. 애니메이션
8799 moveAndConvert ( thumbnailView: thumbnailViewCopy, containerView: containerView, to: absoluteFrame) {
100+ /// 6-4. 띄워줄 뷰 표시
88101 toView. view. isHidden = false
102+ /// 6-5. 썸네일 복사 뷰 제거, 썸네일 뷰 원상복구 (표시)
89103 thumbnailViewCopy. removeFromSuperview ( )
90104 thumbnailView. isHidden = false
105+ /// 6-6. 애니메이션 종료 알림
91106 transitionContext. completeTransition ( true )
92107 }
93108 }
94109
110+ /// 6. Dismiss: 위에서 셀의 위치로 돌아오면서 작아집니다.
95111 if transition == . dismiss, let fromView {
112+ /// 6-1. 시작 뷰 숨김
96113 fromView. view. isHidden = true
97-
114+ /// 6-2. 썸네일 복사 뷰 위치를 시작하는 플레이어 위치부터 시작
98115 thumbnailViewCopy. frame = CGRect ( x: 0 , y: fromView. view. layoutMargins. top, width: containerView. frame. width, height: containerView. frame. width * 0.5625 )
99-
116+ /// 6-3. 애니메이션
100117 moveAndConvert ( thumbnailView: thumbnailViewCopy, containerView: containerView, to: absoluteFrame) {
118+ /// 6-4. 썸네일 복사 뷰 제거, 썸네일 뷰 원상복구 (표시)
119+ thumbnailViewCopy. removeFromSuperview ( )
101120 thumbnailView. isHidden = false
121+ /// 6-6. 애니메이션 종료 알림
102122 transitionContext. completeTransition ( true )
103123 }
104124 }
@@ -113,26 +133,36 @@ extension CollectionViewCellTransitioning {
113133 return thumbnailViewCopy
114134 }
115135
136+ /// Present 때 사용되는 애니메이션
137+ /// 썸네일을 잠깐 축소했다가 확대시키면서 애니메이션이 진행됩니다.
116138 private func makeShrinkAnimator( of thumbnailView: ThumbnailView ) -> UIViewPropertyAnimator {
117139 UIViewPropertyAnimator ( duration: shrinkDuration, curve: . linear) {
118140 thumbnailView. transform = CGAffineTransform ( scaleX: 0.95 , y: 0.95 )
119141 }
120142 }
121143
144+ /// Present, Dismiss 때 사용되는 애니메이션
122145 private func makeExpandContractAnimator( of thumbnailView: ThumbnailView , in containerView: UIView , to frame: CGRect ) -> UIViewPropertyAnimator {
146+ /// 애니메이션 설정
123147 let springTiming = UISpringTimingParameters ( dampingRatio: 0.75 , initialVelocity: CGVector ( dx: 0 , dy: 2 ) )
124148 let animator = UIViewPropertyAnimator ( duration: transitionDuration - shrinkDuration, timingParameters: springTiming)
125149
126150 animator. addAnimations {
127- thumbnailView. transform = . identity
128-
129- if self . transition == . present {
151+ switch self . transition {
152+ case . present:
153+ /// 작아졌던 썸네일 뷰 원상태로
154+ thumbnailView. transform = . identity
155+ /// 썸네일 뷰 Style, Layout 업데이트
130156 thumbnailView. updateStyles ( for: . present)
131157 thumbnailView. updateLayouts ( for: . present)
158+ /// 썸네일 뷰 플레이어뷰 위치로 이동 및 확대
132159 thumbnailView. frame = CGRect ( x: 0 , y: containerView. layoutMargins. top, width: containerView. frame. width, height: containerView. frame. width * 0.5625 )
133- } else {
160+
161+ case . dismiss:
162+ /// 썸네일 뷰 Style, Layout 업데이트
134163 thumbnailView. updateStyles ( for: . dismiss)
135164 thumbnailView. updateLayouts ( for: . dismiss)
165+ /// 인자로 받은 frame위치로 이동 (기존 썸네일 뷰의 절대 프레임)
136166 thumbnailView. frame = frame
137167 }
138168
@@ -153,20 +183,21 @@ extension CollectionViewCellTransitioning {
153183 let shrinkAnimator = makeShrinkAnimator ( of: thumbnailView)
154184 let expandContractAnimator = makeExpandContractAnimator ( of: thumbnailView, in: containerView, to: frame)
155185
156- expandContractAnimator. addCompletion { _ in
157- completion ( )
158- }
159-
160- if transition == . present {
186+ switch transition {
187+ case . present:
188+ shrinkAnimator. startAnimation ( )
189+
161190 shrinkAnimator. addCompletion { _ in
162- thumbnailView. layoutIfNeeded ( )
163191 expandContractAnimator. startAnimation ( )
164192 }
165193
166- shrinkAnimator. startAnimation ( )
167- } else {
194+ case . dismiss:
168195 thumbnailView. layoutIfNeeded ( )
169196 expandContractAnimator. startAnimation ( )
170197 }
198+
199+ expandContractAnimator. addCompletion { _ in
200+ completion ( )
201+ }
171202 }
172203}
0 commit comments