@@ -18,7 +18,7 @@ final class EmotionRegistrationViewController: BaseViewController<EmotionRegiste
1818 static let smallMarbleImageSize : CGFloat = 40
1919 static let emotionLabelWidth : CGFloat = 92
2020 static let emotionLabelHeight : CGFloat = 36
21- static let emotionCollectionViewHeight : CGFloat = 191
21+ static let emotionCollectionViewHeight : CGFloat = 291
2222 static let emotionMarbleImageViewSize : CGFloat = 140
2323 static let emotionMarbleImageViewTopSpacing : CGFloat = 13
2424 static let speechImageTopSpacing : CGFloat = 26
@@ -33,11 +33,12 @@ final class EmotionRegistrationViewController: BaseViewController<EmotionRegiste
3333 static let foromThumbLeadingSpacing : CGFloat = 71
3434 static let handMarbleImageViewBottomSpacing : CGFloat = 7
3535 static let handMarbleImageViewTopSpacing : CGFloat = 50
36- static let infoLabelTopSpacing : CGFloat = 30
36+ static let infoLabelTopSpacing : CGFloat = - 70
3737 static let doubleChevronIconSize : CGFloat = 24
3838 static let doubleChevronIconHorizontalSpacing : CGFloat = 26
3939 static let doubleChevronIconTopSpacing : CGFloat = 10
4040 static let infoViewSize : CGFloat = 0
41+ static let infoSwipeOverlayViewHeight = 100
4142 }
4243
4344 private let smallMarbleScrollView = UIScrollView ( )
@@ -55,14 +56,19 @@ final class EmotionRegistrationViewController: BaseViewController<EmotionRegiste
5556 private let leftDoubleChevronImageView = UIImageView ( )
5657 private let rightDoubleChevronImageView = UIImageView ( )
5758 private let downDoubleChevronImageView = UIImageView ( )
59+ private let infoSwipeOverlayView = UIView ( )
60+ private let hapticGenerator = UISelectionFeedbackGenerator ( )
61+ private let itemSetCount = 7
5862 private var isMarbleHeld = false
5963 private var marbleImageViewMidY : CGFloat ?
6064 private var marbleImageViewPanGesture : UIPanGestureRecognizer ?
6165 private var emotion : Emotion ?
6266 private var dataSource : UICollectionViewDiffableDataSource < Int , Emotion > ?
6367 private var cancellables : Set < AnyCancellable >
68+ private var lastMarbleCellIndex : Int = 0
69+
6470 var itemCount : Int {
65- return ( dataSource? . snapshot ( ) . numberOfItems ?? 0 ) / 3
71+ return ( dataSource? . snapshot ( ) . numberOfItems ?? 0 ) / itemSetCount
6672 }
6773
6874
@@ -121,6 +127,9 @@ final class EmotionRegistrationViewController: BaseViewController<EmotionRegiste
121127 speechLabel. font = BitnagilFont . init ( style: . cafe24Title2, weight: . light) . font
122128 speechLabel. textColor = . clear
123129
130+ infoSwipeOverlayView. backgroundColor = . clear
131+ infoSwipeOverlayView. isUserInteractionEnabled = false
132+
124133 infoLabel. numberOfLines = 0
125134 infoLabel. font = BitnagilFont . init ( style: . body2, weight: . medium) . font
126135 infoLabel. textColor = BitnagilColor . gray50
@@ -160,6 +169,7 @@ final class EmotionRegistrationViewController: BaseViewController<EmotionRegiste
160169 view. addSubview ( handMarbleView)
161170 view. addSubview ( thumbImageView)
162171 view. addSubview ( infoView)
172+ view. addSubview ( infoSwipeOverlayView)
163173 smallMarbleScrollView. addSubview ( smallMarbleStackView)
164174 infoView. addSubview ( infoLabel)
165175 infoView. addSubview ( leftDoubleChevronImageView)
@@ -258,6 +268,12 @@ final class EmotionRegistrationViewController: BaseViewController<EmotionRegiste
258268 make. bottom. equalTo ( thumbImageView. snp. bottom) . offset ( - Layout. handMarbleImageViewBottomSpacing)
259269 make. size. equalTo ( Layout . emotionMarbleImageViewSize)
260270 }
271+
272+ infoSwipeOverlayView. snp. makeConstraints { make in
273+ make. horizontalEdges. equalToSuperview ( )
274+ make. bottom. equalTo ( emotionCollectionView. snp. bottom)
275+ make. height. equalTo ( Layout . infoSwipeOverlayViewHeight)
276+ }
261277 }
262278
263279 override func bind( ) {
@@ -267,11 +283,21 @@ final class EmotionRegistrationViewController: BaseViewController<EmotionRegiste
267283 guard let self = self else { return }
268284
269285 let originalEmotionCount = emotions. count
270- let tripledEmotions = emotions. map ( { $0. copy ( ) } ) + emotions + emotions. map ( { $0. copy ( ) } )
286+ let centerIndex = itemSetCount / 2 + 1
287+ let multipliedEmotions = ( 0 ..< itemSetCount) . flatMap { i in
288+ i == centerIndex ? emotions : emotions. map { $0. copy ( ) }
289+ }
290+
291+ guard
292+ let layout = emotionCollectionView. collectionViewLayout as? EmotionCollectionViewLayout ,
293+ let currentIndex = layout. fetchcurrentIndex ( )
294+ else { return }
295+
296+ lastMarbleCellIndex = currentIndex
271297
272298 var snapshot = NSDiffableDataSourceSnapshot < Int , Emotion > ( )
273299 snapshot. appendSections ( [ 0 ] )
274- snapshot. appendItems ( tripledEmotions )
300+ snapshot. appendItems ( multipliedEmotions )
275301 self . dataSource? . apply ( snapshot, animatingDifferences: false )
276302
277303 self . scrollToIndex ( index: originalEmotionCount)
@@ -350,8 +376,7 @@ final class EmotionRegistrationViewController: BaseViewController<EmotionRegiste
350376 }
351377
352378 private func configureMarbleImageView( ) {
353- marbleImageViewPanGesture = UIPanGestureRecognizer ( target: self , action: #selector( handlePan ( gesture: ) ) )
354- marbleImageViewPanGesture? . cancelsTouchesInView = false
379+ marbleImageViewPanGesture = UIPanGestureRecognizer ( target: self , action: #selector( handleEmotionCollectionViewPanning ( gesture: ) ) )
355380
356381 handMarbleView. layer. cornerRadius = Layout . emotionMarbleImageViewSize / 2
357382 handMarbleView. layer. masksToBounds = true
@@ -377,7 +402,7 @@ final class EmotionRegistrationViewController: BaseViewController<EmotionRegiste
377402 }
378403 }
379404
380- @objc private func handlePan ( gesture: UIPanGestureRecognizer ) {
405+ @objc private func handleEmotionCollectionViewPanning ( gesture: UIPanGestureRecognizer ) {
381406 guard let marbleImageViewMidY else { return }
382407
383408 switch gesture. state {
@@ -454,8 +479,22 @@ extension EmotionRegistrationViewController: UICollectionViewDelegate {
454479}
455480
456481extension EmotionRegistrationViewController : UIScrollViewDelegate {
482+ func scrollViewDidScroll( _ scrollView: UIScrollView ) {
483+ guard
484+ let layout = emotionCollectionView. collectionViewLayout as? EmotionCollectionViewLayout ,
485+ let currentIndex = layout. fetchcurrentIndex ( ) ,
486+ lastMarbleCellIndex != currentIndex
487+ else { return }
488+
489+ lastMarbleCellIndex = currentIndex
490+ hapticGenerator. selectionChanged ( )
491+ hapticGenerator. prepare ( )
492+
493+ }
494+
457495 func scrollViewWillBeginDragging( _ scrollView: UIScrollView ) {
458496 emotionMarbleImageView. isHidden = true
497+ hapticGenerator. prepare ( )
459498 }
460499
461500 func scrollViewDidEndDecelerating( _ scrollView: UIScrollView ) {
@@ -470,7 +509,7 @@ extension EmotionRegistrationViewController: UIScrollViewDelegate {
470509 else { return }
471510
472511 let index = indexPath. row % itemCount
473- if indexPath. row < itemCount / 3 || indexPath. row >= itemCount * 2 / 3 {
512+ if indexPath. row < itemCount / itemSetCount || indexPath. row >= itemCount * ( itemSetCount / 2 + 1 ) / itemSetCount {
474513 scrollToIndex ( index: index)
475514 }
476515 viewModel. action ( input: . selectEmotion( index: index) )
0 commit comments