Skip to content

Conversation

@codeJiwon
Copy link
Member

🌴 작업한 브랜치

✅ 작업한 내용

1. UIPanGestureRecognizer 기반 모달 슬라이드 인터랙션 구현

  • 사용자의 드래그(pan) 제스처에 따라 listContainerView가 상단 네비게이션바 바로 아래까지 슬라이드 업 되도록 구현
  • 슬라이드가 끝났을 때의 위치에 따라 두 가지 상태(navigationBar 아래까지 완전히 확장 / mapView 아래의 기본 위치) 중 하나로 스냅 이동

2. 뷰 이동 범위 상한/하한 설정
제스처에 따라 이동할 수 있는 오프셋을 아래와 같이 정의:

  • fullyCollapsedOffset: mapView를 완전히 덮고 navigationBar 아래에 붙는 위치
  • fullyExpandedOffset: mapView 바로 아래 기본 위치

3. 스냅 위치 판단 로직
제스처가 끝났을 때 mapView 높이의 절반을 기준으로 위/아래 스냅 결정

  • 상단에 가까우면 navigationBar 아래에 고정
  • 하단에 가까우면 mapView 아래 기본 위치로 복귀

4. 스크롤 잠금/해제 로직
listContainerView가 위로 완전히 확장된 경우에만 scrollEnabled = true 처리
하단 위치일 때는 스크롤 비활성화하여 제스처 기반 슬라이딩과의 충돌 방지

❗️PR Point

@objc private func panGestureHandler(sender: UIPanGestureRecognizer) {
        let draggedDistanceY = sender.translation(in: view).y

        // 팬 도중에는 스크롤이 움직이지 않도록 고정
        courseQuestView.listContainerView.contentOffset = .zero

        // 현재 top constraint의 offset (listContainerView가 얼마나 위로 올라갔는지)
        let currentTopOffset = courseQuestView.listTopConstraint?.layoutConstraints.first?.constant ?? 0

        // 팬 드래그 양만큼 새로운 위치 계산
        let proposedTopOffset = currentTopOffset + draggedDistanceY

         ///고정 위치 정의
         /// -fullyCollapsedOffset: navigationBar 아래에 붙은 위치
         /// -fullyExpandedOffset: mapView 아래 기본 위치
        let fullyCollapsedOffset: CGFloat = -courseQuestView.mapView.frame.height
        let fullyExpandedOffset: CGFloat = 0

        // 바운스 방지를 위한 offset 제한
        let boundedTopOffset = min(max(proposedTopOffset, fullyCollapsedOffset), fullyExpandedOffset)

        // 실시간으로 constraint 반영
        courseQuestView.listTopConstraint?.update(offset: boundedTopOffset)

        // 팬 제스처 기준점 초기화
        sender.setTranslation(.zero, in: view)

        /// 팬 동작이 끝났을 때: 위로 붙일지, 아래로 내릴지 결정하는 코드
        if sender.state == .ended {
            // 스냅 기준: 위로 얼마만큼 가까이 올라갔는지를 기준으로 결정
            let snapThreshold = courseQuestView.mapView.frame.height / 2
            let distanceToCollapse = abs(boundedTopOffset - fullyCollapsedOffset)

            if distanceToCollapse < snapThreshold {
                // 위로 절반 이상 올라갔다면: navigationBar 아래로 딱 붙이기
                courseQuestView.listTopConstraint?.update(offset: fullyCollapsedOffset)
                courseQuestView.listContainerView.isScrollEnabled = true
                courseQuestView.courseQuestPlaceCollectionView.isScrollEnabled = true
            } else {
                // 절반 미만이면: 다시 아래로 내려오기 (기본 위치)
                courseQuestView.listTopConstraint?.update(offset: fullyExpandedOffset)
                courseQuestView.listContainerView.isScrollEnabled = false
                courseQuestView.courseQuestPlaceCollectionView.isScrollEnabled = false
            }

            UIView.animate(withDuration: 0.25, delay: 0, options: [.curveEaseInOut]) {
                self.view.layoutIfNeeded()
            }
        }
    }

📸 스크린샷

설명
ScreenRecording_07-04-2025.21.MOV
ScreenRecording_07-04-2025.22.MOV

@codeJiwon codeJiwon self-assigned this Jul 4, 2025
@codeJiwon codeJiwon linked an issue Jul 4, 2025 that may be closed by this pull request
@codeJiwon codeJiwon added the Style 🎨 UI 작업 label Jul 4, 2025
Copy link
Collaborator

@Johyerin Johyerin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

변경 내용 확인했습니다. 수고하셨습니다!

$0.bottom.equalToSuperview()
$0.horizontalEdges.equalTo(listContainerView.frameLayoutGuide)
$0.height.equalTo(357)
$0.height.equalTo(UIScreen.main.bounds.height - 169)
Copy link
Collaborator

@Johyerin Johyerin Jul 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1

스크롤 뷰 가장 하단으로 내렸을 때 퀘스트 셀 하단이 잘리는 현상이 보여서 수정해주셔야 할 것 같습니다!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

보상 버튼은 추후 제거 예정이라 더미로 남겨두라는 전달을 받았고, 어차피 스크롤 뷰 하단에 붙일 예정이었기 때문에 크게 고려하지 않았습니다. 다만, QA를 위해 일단 잘리지 않도록 임의로 처리해두겠습니다!

Copy link
Collaborator

@Johyerin Johyerin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

고생하셨습니다앙👏👏👏

@codeJiwon codeJiwon merged commit b9ab4f6 into main Jul 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feat] 코스퀘스트 스크롤 구현

3 participants