Skip to content

Commit cd3d592

Browse files
committed
chore 히어로 애니메이션 주석 추가
1 parent 63d2364 commit cd3d592

File tree

2 files changed

+53
-20
lines changed

2 files changed

+53
-20
lines changed

Projects/Features/MainFeature/Sources/Utilities/CollectionViewCellTransitioning.swift

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}

Projects/Features/MainFeature/Sources/ViewControllers/BroadcastCollectionViewController.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,8 @@ extension BroadcastCollectionViewController: UICollectionViewDelegate {
132132
public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
133133
guard let channel = dataSource?.itemIdentifier(for: indexPath) else { return }
134134
guard let viewController = factory?.make(channelID: channel.id, title: channel.name, owner: channel.owner, description: channel.description) else { return }
135+
136+
/// 히어로 애니메이션 전환 적용
135137
viewController.modalPresentationStyle = .overFullScreen
136138
viewController.transitioningDelegate = transitioning
137139
present(viewController, animated: true)

0 commit comments

Comments
 (0)