iOS) 무한스크롤 구현하기 핸들링하기

2 minute read

전문용어는 아니지만 나는 다음의 효과에 대해서 무한 스크롤이라고 명명하고 글을 작성하기로 했다.

  • 우리가 컨텐츠를 스크롤하다보면 마지막 컨텐츠에 닿으면 스크롤이 늘어나는 경험을 한적이 있었을 것이다. 우리는 이걸 인파이나이트 어메이징 스크롤 즉, 무한 스크롤이라고 말해보자 😉
  • 보통 무한 스크롤이라면 여러개의 데이터(이미지와 텍스트)를 서버가 보내고 프론트가 받기에 부담스럽기 때 사용한다. 그래서 클라이언트가 스크롤이 마지막에 닿으면 다음 데이터를 서버에게 요구하게된다.
  • 서버가 요구하는 보통 page, index, offset 이러한 분류 번호를 가지고 다음 스크롤의 데이터를 요청하게 된다.

  • UICollectionViewDelegate 가 UIScrollViewDelegate 를 채택하기 때문에 scrollViewDidScroll(_:) 를 사용할 수 있다.
// MARK: - UICollectionViewDelegate

extension GroupViewController: UICollectionViewDelegate {
    // ✅ Tells the delegate when the user scrolls the content view within the receiver.
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        // ✅ 남은 content size 의 높이보다 스크롤을 많이 했다. 즉, 다음 컨텐츠가 필요한 경우.
        if scrollView.contentOffset.y > scrollView.contentSize.height - scrollView.bounds.height {
            // ✅ 한번만 서버통신을 하도록 하기 위한 조건문.
            if isInfiniteScroll {
                isInfiniteScroll = false
                // ✅ offset 증가. 다음 오프셋 데이터를 서버통신의 파라미터로 추가하기 위함.
                offset += 1
                
                // ✅ 서버통신. 탈출클로저를 통해서 서버통신이 끝난 후, isInfiniteScroll 변수를 true 로 변경해 주면 됩니다.
                fetchListWithAPI(offset: offset) {
                    self.isInfiniteScroll = true
                }
            }
        }
    }
}

📌 contentOffset

scroll view 의 원점에서 content view 의 원점까지 얼마나 떨어졌는지 나타냄.

즉, 사용자가 스크롤 한 후에 있는 지점을 의미한다.

📌 contentSize

content view 의 사이즈.

즉, scroll view 가 길어진 총 사이즈를 의미한다.

출처 : https://betterprogramming.pub/contentoffset-contentinset-and-contentsize-of-a-uiscrollview-5ae8beb0f1db

자 그러면 코드를 살펴볼까요?

scrollView.contentOffset.y > scrollView.contentSize.height - scrollView.bounds.height {
  • scrollView.contentSize.height - scrollView.bounds.height

스크롤뷰의 길어질 수 있는 총 높이에서 현재 스크롤뷰의 높이를 제외하면 앞으로 남은 길어질 수 있는 높이가 된다 . 컨텐츠가 늘어나지 않은 이상 고정적인 값.

  • scrollView.contentOffset.y > ...

남은 길어질 수 있는 높이보다 스크롤한 y 좌표가 크다. 즉, 이미 컨텐츠를 다보았다는 의미이다. 이때 서버통신을 통해서 데이터를 받아와서 리로드 해주면 된다.

✅ isInfiniteScroll

코드를보면 위와 같은 변수를 볼 수 있다.

관련 조건문을 사용하지 않은채 코드를 짜게되면 수십번 서버통신을 요청하는 현상을 볼 수 있다. 한번 끝에 닿게되면 한번만 서버통신을 요청해야하는데 계속 요청하는 상태를 말이다.

contentOffset.y 값이 한번 스크롤하면 도달한 값이 아닌 움직이는 순간순간의 값이다보니 그 이상 스크롤하게되면 그만큼 계속 실행되게 된다.

그래서 그걸 막기위해서 isInfiniteScroll 변수를 사용해보았다.

// isinfinitesScroll 초기값은 true.
if isInfiniteScroll {
        isInfiniteScroll = false
        // ✅ offset 증가. 다음 오프셋 데이터를 서버통신의 파라미터로 추가하기 위함.
        offset += 1
                
        // ✅ 서버통신. 탈출클로저를 통해서 서버통신이 끝난 후, isInfiniteScroll 변수를 true 로 변경해 주면 됩니다.
        fetchListWithAPI(offset: offset) {
            self.isInfiniteScroll = true
        }
}

첫 서버통신이 끝나기 전까지 조건문을 들어올 수 없도록 isInfiniteScroll 의 값을 false 로 설정했다.

오프셋을 증가시켜서 서버에 새로운 데이터 목록을 요청했다.

탈출 클로저를 활용해서 서버통신이 끝난 후 isInfiniteScroll 의 값을 true 만들어서 모든 컨텐츠를 스크롤한 후 조건문에 다시금 들어올 수 있도록 했다.

Categories:

Updated: