iOS) 무한스크롤 구현하기 핸들링하기
전문용어는 아니지만 나는 다음의 효과에 대해서 무한 스크롤이라고 명명하고 글을 작성하기로 했다.
- 우리가 컨텐츠를 스크롤하다보면 마지막 컨텐츠에 닿으면 스크롤이 늘어나는 경험을 한적이 있었을 것이다. 우리는 이걸 인파이나이트 어메이징 스크롤 즉, 무한 스크롤이라고 말해보자 😉
- 보통 무한 스크롤이라면 여러개의 데이터(이미지와 텍스트)를 서버가 보내고 프론트가 받기에 부담스럽기 때 사용한다. 그래서 클라이언트가 스크롤이 마지막에 닿으면 다음 데이터를 서버에게 요구하게된다.
-
서버가 요구하는 보통 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 가 길어진 총 사이즈를 의미한다.
자 그러면 코드를 살펴볼까요?
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 만들어서 모든 컨텐츠를 스크롤한 후 조건문에 다시금 들어올 수 있도록 했다.