세로 스크롤(무한 스크롤이라고 칭하겠음)을 구현해야했다!
처음 구현해보는 것이라 방법을 찾아보았는데, UICollectionView 사용하는 방법과 UIPageViewController 사용하는 방법이 있었다.
UICollectionView가 조금은 더 익숙해서 UICollectionView를 사용해서 구현해보고 추후에 UIPageViewController를 적용해봐야겠다고 생각했다.
UICollectionView:
isPagingEnabled = true
속성만 추가하면 페이징 기능 구현 가능UIPageViewController:
UICollectionView:
UIPageViewController:
UICollectionView:
UIPageViewController:
UICollectionView 페이징이 적합한 경우:
UIPageViewController가 적합한 경우:
private var itemDetailCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.minimumLineSpacing = 0
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.backgroundColor = .clear
collectionView.showsVerticalScrollIndicator = false
collectionView.isPagingEnabled = true // 페이징 기능 활성화
return collectionView
}()
scrollDirection = .vertical
: 세로 방향 페이징 설정isPagingEnabled = true
: UIKit의 페이징 동작 활성화minimumLineSpacing = 0
: 페이지 간 여백 제거override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
if let layout = itemDetailCollectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.itemSize = itemDetailCollectionView.bounds.size
}
}
cell의 크기 != 화면 크기 였기 때문에,
viewDidLayoutSubviews에서 view의 size를 측정하지 않으면 올바르게 페이징이 되지 않는 이슈가 있었다.
나의 경우에는 cell의 크기를 화면 크기에 맞춘 것이 아니라, cell 안에도 따로 scrollView가 내장되어 있었기 때문에 해당 메서드를 사용했다.
itemDetailCollectionView.rx.didEndDecelerating
.subscribe(onNext: { [weak self] in
guard let self = self else { return }
let visibleIndexPaths = self.itemDetailCollectionView.indexPathsForVisibleItems
let sortedIndexPaths = visibleIndexPaths.sorted(by: { $0.item < $1.item })
if let firstIndexPath = sortedIndexPaths.first {
self.currentIndex = firstIndexPath.item
self.viewModel.updateCurrentIndex(firstIndexPath.item)
self.saveRecentItem()
}
})
.disposed(by: disposeBag)
작동 방식:
1. 스크롤이 멈추면(didEndDecelerating
) 현재 화면에 보이는 셀들의 IndexPath를 가져옴
2. IndexPath들을 정렬하여 가장 위에 있는 셀을 현재 페이지로 결정
3. 이에 따라 상태 업데이트
스크롤이 잘 작동한다!