ios/UI구현

[iOS, Swift] 네이버지도의 BottomSheet

2023. 7. 27. 18:51
목차
  1. 구현아이디어
  2. 구현과정에서의 오류
  3. 결과 화면

 

 

  • 네이버 지도의 Bottom Sheet 구현
  • UIPanGestureRecognizer를 사용하여 사용자의 터치에 따른 화면(View or ViewController)의 이동

구현아이디어

UIPanGestureRecognizer를 이용하여 띄워놓은 view를 사용자의 터치 이벤트에따라 view를 움직이게 하는 bottomSheet를 구현하고자 했습니다.

구현과정에서의 오류

  1. UIPanGestureRecognizer의 동작방식에 대한 이해부족 UIPanGestureRecognizer는 superView와의 관계를 통해 bottomSheetView의 위치를 잡도록 되어있습니다. 하지만 이 부분을 놓쳐 bottomSheetView의 독자적인 height constraint를 변경하여 구현 하려고 했고 실행 결과 몇번의 제스쳐에는 반응을 했지만 이 후 bottomSheetView의 위치를 잡을 수 없어 bottomSheetView가 움직이지 않았습니다. → superView와 bottomSheetView에 top constraint를 주어 해결하였습니다.
  2. UIPanGestureRecognizer의 구현 과정에서 다음과 같은 recognizer.setTranslation(CGPoint.zero, in: bottomSheetView) 메소드를 사용하였는데 translation메소드는 드래그가 처음 시작된 지점으로부터 이동좌표를 반환 합니다. 하지만 우리는 뷰를 이동시켰기 때문에 드래그가 처음 시작된 지점의 좌표는 더 이상 뷰의 좌표가 아닙니다. 이때 UIPanGestureRecognizer는 뷰가 이동했다는 사실을 알지 못하므로bottomSheetView이 이동된 좌표의 값을 zero로 초기화 해주었습니다. 이말은 즉 translationY(recognizer.translation(in: bottomSheetView).y)의 값을 bottomSheetView.frame.origin.y의 값에 계속해서 더해 주어야 하므로 self.bottomSheetView.frame.origin.y += translationY 와 같은 코드를 쓰게 됩니다.
  3. UIView.animate 함수 내부, 외부에서 구현의 차이
@objc private func didPan(_ recognizer: UIPanGestureRecognizer) {
        let translationY = recognizer.translation(in: bottomSheetView).y
        recognizer.setTranslation(CGPoint.zero, in: bottomSheetView)
        
        self.bottomSheetView.frame.origin.y += translationY
        
        if recognizer.state == .ended {
            let top = self.view.frame.height * 0.8
            let middle = self.view.frame.height / 2
            let bottom = self.view.frame.height * 0.2
            
            if self.bottomSheetView.frame.origin.y > (top + middle) / 2 {
                self.bottomSheetView.frame.origin.y = top
            } else if self.bottomSheetView.frame.origin.y <= (top + middle) / 2 &&
                        self.bottomSheetView.frame.origin.y > (middle + bottom) / 2{
                self.bottomSheetView.frame.origin.y = middle
            } else {
                self.bottomSheetView.frame.origin.y = bottom
            }
        }
        
        UIView.animate(withDuration: 0.2) {
            self.view.layoutIfNeeded()
        }
    }
@objc private func didPan(_ recognizer: UIPanGestureRecognizer) {
        let translationY = recognizer.translation(in: bottomSheetView).y
        recognizer.setTranslation(CGPoint.zero, in: bottomSheetView)
        
        UIView.animate(withDuration: 0.2) {
            self.bottomSheetView.frame.origin.y += translationY
            
            if recognizer.state == .ended {
                let top = self.view.frame.height * 0.8
                let middle = self.view.frame.height / 2
                let bottom = self.view.frame.height * 0.2
                
                if self.bottomSheetView.frame.origin.y > (top + middle) / 2 {
                    self.bottomSheetView.frame.origin.y = top
                } else if self.bottomSheetView.frame.origin.y <= (top + middle) / 2 &&
                            self.bottomSheetView.frame.origin.y > (middle + bottom) / 2{
                    self.bottomSheetView.frame.origin.y = middle
                } else {
                    self.bottomSheetView.frame.origin.y = bottom
                }
            }
        }
    }

상단의 코드는 외부에서 구현하여 animations 블럭에 레이아웃을 변경하라는 코드를 작성하였고 하단의 코드는 animations 블럭 내부에 직접 구현한 형태입니다. 상단의 코드에서는 bottomSheetView의 변화에 대해 animation이 적용되지 않았고 하단의 코드에서는 적용되었습니다.

그 이유를 알아보았는데(추측) 다음은 animations 내부에 정의 할수 있는 것들입니다

animations (필수)

실제로 애니메이션이 될 부분을 정의한다.

frame / bounds / center : 뷰의 위치와 크기

transform : 좌표 행렬값

alpha : 투명도

backgroundColor: 배경색

contentStretch : 확대 / 축소 영역

hidden과 같이 중간값 계산이 불가능한 속성은 애니메이션이 안된다.

위의 내용과 layoutIfNeeded라는 이름에서 유추하여 생각해보면 제약조건을 통해 뷰의 위치를 구성하였을때는 animations 내부에 layoutIfNeeded를 통해 뷰의 레이아웃을 요청할 수 있지만 frame이나 bounds를 통해 뷰의 위치를 구성할때는 animations 내에 직접구현을 하면 되지 않을까라고 추측해봤습니다.

결과 화면

'ios > UI구현' 카테고리의 다른 글

[iOS, Swift] AppStore layout만들어보기(UICollectionView, CompositionalLayout 활용)  (0) 2023.07.27
[iOS, Swift] 네이버 웹툰 메인 페이지(UIPageViewController, UISegnmentControl 활용)  (0) 2023.07.27
[iOS, Swift] Sticky Header(배달의민족, 당근마켓)  (0) 2023.07.27
[Swift] UICollectionView - Compositional Layout section의 동적인 높이 조절  (0) 2023.05.30
  1. 구현아이디어
  2. 구현과정에서의 오류
  3. 결과 화면
'ios/UI구현' 카테고리의 다른 글
  • [iOS, Swift] AppStore layout만들어보기(UICollectionView, CompositionalLayout 활용)
  • [iOS, Swift] 네이버 웹툰 메인 페이지(UIPageViewController, UISegnmentControl 활용)
  • [iOS, Swift] Sticky Header(배달의민족, 당근마켓)
  • [Swift] UICollectionView - Compositional Layout section의 동적인 높이 조절
chobo5
chobo5
개발 기록
chobo5's blog개발 기록
전체
오늘
어제
chobo5
chobo5's blog
chobo5
  • 분류 전체보기
    • ios
      • 문법
      • UIKit
      • UI구현
      • 기타
    • IT
    • Java
      • 기초
      • Spring
      • JPA
    • Algorithm
    • OOP
    • SQL

블로그 메뉴

  • 홈
  • 태그
  • 방명록

인기 글

태그

  • Swift
  • Lazy
  • didset
  • getter
  • static
  • 프로퍼티
  • property
  • restapi
  • API
  • setter

최근 글

hELLO · Designed By 정상우.
chobo5
[iOS, Swift] 네이버지도의 BottomSheet
상단으로

티스토리툴바

개인정보

  • 티스토리 홈
  • 포럼
  • 로그인

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.