티스토리 뷰

Swift

collectionView paging 해보기!

진태우 2018. 7. 20. 15:58

collectionView에 간단히 paging을 설정할 수 있는 프로퍼티가 있다.

 

collectionView.isPagingEnabled = true

 

위 코드와 같이 간단히 가능하다.

하지만 이 코드로는 상하좌우에 여백이 생기면 스크롤 시 어그러지는 현상이 발생된다.

난 아래와 같은 페이징 효과를 원했다!!!

 

 

 

그래서 검색을 통해 코드를 보고 내가 원하는대로 만들어 보았다.

아래는 collectionView에 대한 초기 설정이다.

 

class ViewController: UIViewController {
    @IBOutlet weak var collectionView: UICollectionView!
    let itemColors = [UIColor.red, UIColor.yellow, UIColor.blue, UIColor.green]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        // width, height 설정
        let cellWidth = view.frame.width - 100
        let cellHeight = view.frame.height - 100
        
        // 상하, 좌우 inset value 설정
        let insetX = (collectionView.bounds.width - cellWidth) / 2.0
        let insetY = (collectionView.bounds.height - cellHeight) / 2.0
        
        let layout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
        layout.itemSize = CGSize(width: cellWidth, height: cellHeight)
        layout.minimumLineSpacing = 15
        layout.scrollDirection = .horizontal
        collectionView.contentInset = UIEdgeInsets(top: insetY, left: insetX, bottom: insetY, right: insetX)
        
        collectionView.delegate = self
        collectionView.dataSource = self
        
        // 스크롤 시 빠르게 감속 되도록 설정
        collectionView.decelerationRate = UIScrollViewDecelerationRateFast
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}

 

scrollViewWillEndDragging 은 사용자가 스크롤을 하고 스크린과 손이 떨어졌을 때 호출되는 메서드이다.

이를 통해 스크롤 할 때, content의 위치를 조정하여 페이징되는 효과를 낼 수 있었다.

 

우선 메서드의 파라미터가 무엇을 나타내는지는 아래 공식 홈페이지에 잘 나와 있었다.

scrollViewwillEndDragging(_:withVelocity:targetContentOffset:) - 공식 홈페이지

 

간단히 적어보면

scrollView - 터치를 종료한 스크롤 뷰 

velocity - 스크롤하다 터치 해제시 속도

targetContentOffset - 스크롤 속도가 줄어들어 정지될 때 예상되는 위치

 

아래 코드와 설명을 나름... 정리해 보았다...

 

extension ViewController : UIScrollViewDelegate
{
    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer)
    {
        // item의 사이즈와 item 간의 간격 사이즈를 구해서 하나의 item 크기로 설정.
        let layout = self.collectionView.collectionViewLayout as! UICollectionViewFlowLayout
        let cellWidthIncludingSpacing = layout.itemSize.width + layout.minimumLineSpacing
        
        // 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 {
            roundedIndex = ceil(index)
        }
        
        // 위 코드를 통해 페이징 될 좌표값을 targetContentOffset에 대입하면 된다.
        offset = CGPoint(x: roundedIndex * cellWidthIncludingSpacing - scrollView.contentInset.left, y: -scrollView.contentInset.top)
        targetContentOffset.pointee = offset
    }
}

 

설명과 정리를 잘 하지 못하여 간단하게 예제를 만들어 보았다.

하단에 예제와 가장 도움을 많이 받은 영상을 첨부 해 놓았다.

 

CollectionViewPagingExample - Github

 

UICollectionView with Swift: Build Carousel Like Home Screen - YouTube

 

정리하며 알게된 사실... "swift collectionView paging" 으로 많이 검색했는데 "swift carousel effect"라고 검색하면 더 잘 나오는 것 같다....

 

 

 

 


 

 

페이징 할 때 하나씩만 넘어가도록 하는 코드 업데이트 했습니다.

 

아래는 기존 scrollViewWillEndDragging 메소드에서 수정될 부분만을 보여주기 위한 코드입니다.

extension ViewController : UIScrollViewDelegate
{
    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer)
    {

        ...


        if scrollView.contentOffset.x > targetContentOffset.pointee.x {
            roundedIndex = floor(index)
        } else {
            roundedIndex = ceil(index)
        }
        

        ...
    }
}

 

 

이제 위 코드 부분을 아래와 같이 수정해 보았습니다.

var currentIndex: CGFloat = 0    // 현재 보여지고 있는 페이지의 인덱스

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

    ...


    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)
    }
        
    if currentIndex > roundedIndex {
        currentIndex -= 1
        roundedIndex = currentIndex
    } else if currentIndex < roundedIndex {
        currentIndex += 1
        roundedIndex = currentIndex
    }
        

    ...
}

 

기존에는 스크롤한 값에 대해 페이징되는 인덱스 값을 구하여, 인덱스 크기만큼 페이징 처리를 했습니다.

업데이트 된 코드에서는 페이징되는 인덱스 크기를 1로 수정하여 하나씩만 페이징 되도록 처리했습니다.

 

 

수정된 코드는 깃허브에 업데이트 되어 있습니다!! 🤫🤫🤫

 

 

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함