Swipe에 따라 움직이는 상단바 구현

Duna·2021년 7월 22일
0
post-thumbnail


왜 Swipe에 맞춰서 움직이세요?

너무 구현해보고 싶어서 다양한 도전끝에 길을 찾았습니다.
공유해볼게요!

...Λ_Λ
(ㆍωㆍ)つ━☆
⊂   ノ    .뾰
し-J   °。로
´¨)
.. .· ´¸.·롱´¨) ¸.·¨)
(¸.·´ (????¸.'*


저는 저 안에

[backButton]

[bottomLineView]

[CollectionView]

이렇게 전체적인 뷰를 구성해줬어요.

이렇게 구성되어진 뷰를 기반으로 만들었기 때문에, 저랑 다르게 레이아웃을 잡았을 경우에는 다른 방법을 찾는 걸 추천드립니다!

저는 일단 CollectionView의 기반인 ScrollView가 Scroll되는걸 감지해서

저 bottomLineView가 움직이게 해줬어요.

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) { }

이 함수를 사용해서 ScrollView의 Dragging이 끝날때쯤에 현재 CollectionView의 index를 감지해서 해당 인덱스에 맞게 LineView가 움직이도록 했어요.

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
				let cellWidthIncludingSpacing = UIScreen.main.bounds.size.width
        
				// targetContentOff을 이용하여 x좌표가 얼마나 이동했는지 확인 
				// 이동한 x좌표 값과 item의 크기를 비교하여 몇 페이징이 될 것인지 값 설정
        var offset = targetContentOffset.pointee
        let index = (offset.x + scrollView.contentInset.left) / cellWidthIncludingSpacing
        var roundedIndex = round(index)
        

				// scrollView, targetContentOffset의 좌표 값으로 스크롤 방향을 알 수 있다. 
				// index를 반올림하여 사용하면 item의 절반 사이즈만큼 스크롤을 해야 페이징이 된다. 
				// 스크로로 방향을 체크하여 올림,내림을 사용하면 좀 더 자연스러운 페이징 효과를 낼 수 있다.
        if scrollView.contentOffset.x > targetContentOffset.pointee.x {
            roundedIndex = floor(index)
        } else if scrollView.contentOffset.x < targetContentOffset.pointee.x {
            roundedIndex = ceil(index)
        } else {
            roundedIndex = round(index)
        }
        
				// 기존에는 스크롤한 값에 대해 페이징되는 인덱스 값을 구하여, 인덱스 크기만큼 페이징 처리를 했습니다.
				// 업데이트 된 코드에서는 페이징되는 인덱스 크기를 1로 수정하여 하나씩만 페이징 되도록 처리했습니다.
        if currentIndex > roundedIndex {
            currentIndex -= 1
            roundedIndex = currentIndex
            moveNegativeDirection()
        } else if currentIndex < roundedIndex {
            currentIndex += 1
            roundedIndex = currentIndex
            movePositiveDirection()
        }
        
				// 위 코드를 통해 페이징 될 좌표값을 targetContentOffset에 대입하면 된다.
        offset = CGPoint(x: roundedIndex * cellWidthIncludingSpacing - scrollView.contentInset.left, y: -scrollView.contentInset.top)
        targetContentOffset.pointee = offset
}

// + 방향으로 움직임
// 전체 width사이즈에서 현재 가지고 있는 text의 갯수만큼 나눈걸 index만큼 곱해주면
// index가 클 수록 멀게 이동한다
func movePositiveDirection() {
        UIView.animate(withDuration: 0.3, animations: {
            self.lineView.transform = CGAffineTransform(translationX: UIScreen.main.bounds.size.width/self.textCount * self.currentIndex, y: 0)
        })
}
    
// - 방향으로 움직임
// 전체 width사이즈에서 현재 인덱스를 빼준다
// index가 작아질수록 원래 자리로 돌아온다.
func moveNegativeDirection() {
        UIView.animate(withDuration: 0.3, animations: {
            self.lineView.transform = CGAffineTransform(translationX: UIScreen.main.bounds.size.width - UIScreen.main.bounds.size.width/self.textCount * (self.textCount - self.currentIndex), y: 0)
        })
}

복잡하죠..?

  • cellWidthIncludingSpacing
    cellWidthIncludingSpacing를 스크린의 width로 지정했습니다.
    나중에 cell 하나 하나의 크기를 알아야지 전체 스크롤해서 현재 index가 몇인지 알 수 있기 때문이지요.

  • offset
    현재 target이 되는 content의 좌표를 나타내고 있어요.

  • index
    현재 offset.x 좌표와 scrollView의 왼쪽 inset를 더한 다음에 셀 하나의 크기로 나눠서 현재 index로 넣어줬어요.

  • roundedIndex
    roundedIndex를 통해서 계산한 index를 반올림했습니다.
    뒤에 소수점이 생기는데 만약 소수점이 0.5 이상이면 위로 올리고 나머지는 그 밑으로 계산했어요.

profile
더 멋진 iOS 개발자를 향해

0개의 댓글