Custom ScrollPaging
- UICollectionViewFlowLayout의 targetContentOffset을 overriding 하여 paging 설정
targetContentOffset(forProposedContentOffset:, withScrollVelocity:)
- 파라미터인 forProposedContentOffset, withScrollingVelocity 사용
- forProposedContentOffset: 스크롤하고 난 뒤의 적절한 offset을 사용
- withScrollingVelocity: Scroll에 따른 velocity(왼쪽 스크롤 -, 오른쪽 스크롤 +)
CollectionView Paging예시
class SnappingCollectionViewFlowLayout: UICollectionViewFlowLayout {
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint,
withScrollingVelocity velocity: CGPoint) -> CGPoint {
guard let collectionView = self.collectionView else {
return super.targetContentOffset(forProposedContentOffset: proposedContentOffset,
withScrollingVelocity: velocity)
}
let itemWidth = itemSize.width + minimumInteritemSpacing
let contentOffset = collectionView.contentOffset.x - collectionView.adjustedContentInset.left
let currentOffset = proposedContentOffset.x - collectionView.adjustedContentInset.left
let maxPage = Int(ceil((collectionView.contentSize.width
- collectionView.adjustedContentInset.left
- collectionView.adjustedContentInset.right) / itemWidth))
var page = 0
let contentPage = Int(round(contentOffset / itemWidth))
let proposedPage = Int(round(currentOffset / itemWidth))
if abs(velocity.x) < 2 {
if abs(velocity.x) < 0.2 {
page = contentPage
} else if velocity.x < 0 {
page = Int(ceil(contentOffset / itemWidth)) > 0 ? Int(ceil(contentOffset / itemWidth)) - 1 : 0
} else {
page = contentPage < maxPage ? contentPage + 1 : contentPage
}
} else {
page = proposedPage
}
var offsetX = CGFloat(page) * itemWidth - collectionView.adjustedContentInset.left
let minOffsetX = -collectionView.adjustedContentInset.left
let maxOffsetX = CGFloat(maxPage) * itemWidth - collectionView.adjustedContentInset.left
offsetX = max(min(offsetX, maxOffsetX), minOffsetX)
return CGPoint(x: offsetX, y: proposedContentOffset.y)
}
}
- itemWidth: cell의 Size + cell의 spacing이 있을 시 고려(minimumInteritemSpacing)
- contentOffset: collectionView의 스크롤한 현재 Offset, cell의 왼쪽 마진이 있을시 고려(adjustedContentInset.left)
- currentOffset: proposedContentOffset을 사용한 스크롤뒤 예상되는 Offset
- maxPage: 최대 ScrollPage 제한((contentSize - Inset) / cellWidth))
- contentPage: velocity가 2이하일 경우 paging을 위해 사용
- proposedPage: proposedContentOffset을 사용해 자연스러운 페이징을 위해 사용
- offsetX, minOffsetX, maxOffsetX: 스크롤의 최대 범위 지정(paging error방지)
Why Use ContentPage?
velocity가 2 이하일 경우 proposedContentOffset을사 용해 paging을 할 경우 offset의 편차가 적어 페이징이 안되고 툭툭 끊기는 현상 발생
실행 화면
'swift' 카테고리의 다른 글
Biometric Authentication (0) | 2022.08.31 |
---|---|
DropDown 오픈소스 라이브러리 만들기 (0) | 2022.08.10 |
RxDataSources (0) | 2022.05.07 |
RxSwift UnitTest 해보기(RxTest, RxNimble) (0) | 2022.03.10 |
Tuist로 프로젝트 관리해보기 (0) | 2022.03.05 |