개발을 시작하는 이야기

CollectionView를 활용한 이미지 슬라이드 적용 하기_2 본문

개발 이야기/Swift

CollectionView를 활용한 이미지 슬라이드 적용 하기_2

Teiresias 2022. 6. 14. 18:34

지난번 글에 이어서 ProgressView 부터


이제는 ProgressView에서 Cell의 순서에 맞게 표시해주도록 설정을 해주어야 한다.

 

Apple Developer Documentation

 

developer.apple.com

일단 progress에서 현재 상황을 알려줄 변수를 하나 작성해주었다.

//MARK: - Data
var progress: Progress?

그리고 이제 진행상황에 맞추어 completedUnitCount를 업데이트 해주면 된다. 하지만 이때 주의할점은 최초 로드시에는 0이 아닌 1이여야 한다. 처음 로드하게 되면 첫 페이지가 보여지고 있어야 하기 때문이다.

private func configureProgressView() {
    progressView.progress = 0.1
    progress = Progress(totalUnitCount: Int64(colors.count))
    progress?.completedUnitCount = 1
    progressView.setProgress(Float(progress!.fractionCompleted), animated: false)
}
progressView.progress = 0.1: progress의 위치 (0 ~ 1)
progressView.setProgress(_:animated:): progress의 위치 + 애니메이션 적용 (0 ~ 1)

이제 스크롤이 되는 것을 추적해서 스크롤시 completedUnitCount를 재설정 해주면 된다. 이때 사용할 메서드는  UIScrollViewDelegate의 scrollViewDidEndDecelerating(_ scrollView: UIScrollView)를 사용했다. scrollViewDidEndDecelerating 메서드는  스크롤이 종료된 후, 스크롤이 완전히 멈췄을때 발생한다.

UIScrollViewDelegate는 UICollectionVIewDelegate가 상속받고 있기 때문에 UICollectionVIewDelegate에 선언해주었다.

extension ViewController: UICollectionViewDelegate {
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        var item = visibleCellIndexPath().item
        if item == colors.count * 3 - 2 {
            item = colors.count * 2
        } else if item == 2 {
            item = colors.count + 2
        }
        
        collectionView.scrollToItem(at: IndexPath(item: item, section: 0),
                                    at: .centeredHorizontally,
                                    animated: false)
        
        let unitCount: Int = item % colors.count + 1
        progress?.completedUnitCount = Int64(unitCount)
        progressView.setProgress(Float(progress!.fractionCompleted), animated: false)
    }
}

현재 보여지는 View를 확인해서  마지막에 도착하거나 처음으로 도착하게 되면 가운데로 보내주는 역할을 한다. 특이점은 앞뒤로 2개의 여유를 갖고 움직인다는점인데, 이는 빠르게 스크롤 하거나 하는 경우에 대비해서 여유를 두고 이동시켜 주었다. 하지만 슬라이드의 크기가 적은경우라면  문제가 발생할 수 있으니 사용하는 환경에 따라서 적절한 크기를 고려해주어야 한다.

 

visibleCellIndexPath().item 메서드는 현재 보이는 collectionVIew의 IndexPath를 return해준다.

private func visibleCellIndexPath() -> IndexPath {
    return collectionView.indexPathsForVisibleItems[0]
}

이제 일정 시간마다 자동으로 슬라이딩 되도록 Timer를 적용해주면 완성이다. Timer를 만들때 주의해야할 요소가 많다. 시간마다 계속해서 반복되는 요소이기 때문에 메모리와 관련되 주의를 요한다.

 

일단은 타이머를 시작하는 함수를 만들어준다.

//MARK: - Data
var timer: Timer?

Timer를 시작하는 함수 invalidateTimer()와 초기화 하는 함수 activateTimer()를 만들어준다.

private func invalidateTimer() {
    timer?.invalidate()
}

private func activateTimer() {
    timer = Timer.scheduledTimer(timeInterval: 3,
                                 target: self,
                                 selector: #selector(timerCallBack),
                                 userInfo: nil,
                                 repeats: true)
}

activateTimer는 첫 화면이 로드되는 동시에 시작해야 하기 때문에 ViewDidLoad에 넣어주고, timeInterval로 3초에 한번씩 넘어가도록 하기 위한 #selector로 timerCallBack selector를 만들어준다.

@objc func timerCallBack() {
    var item = visibleCellIndexPath().item
     if item == colors.count * 3 - 1 {
         collectionView.scrollToItem(at: IndexPath(item: colors.count * 2 - 1, section: 0),
                                   at: .centeredHorizontally,
                                   animated: false)
         item = colors.count * 2 - 1
     }

     item += 1
    collectionView.scrollToItem(at: IndexPath(item: item, section: 0),
                               at: .centeredHorizontally,
                               animated: true)
     let unitCount: Int = item % colors.count + 1
     progress?.completedUnitCount = Int64(unitCount)
     progressView.setProgress(Float(progress!.fractionCompleted), animated: false)
}

이제는 화면이 실행되면 자동으로 timeInterval마다 화면이 넘어가게 된다. 하지만 유저가 임의로 조작을 하게 되면 조작한 시점을 기준으로 timeInterval이 진행될 수 있도록 설정해 주어야 한다.

extension ViewController: UICollectionViewDelegate {
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        invalidateTimer()
        activateTimer()
        
        ...
    }
}

그래서 scrollViewDidEndDecelerating메서드가 실행이 될때 invalidateTimer()과 activateTimer()가 실행되도록 해주었다.


해당 코드는 개인 Github에서 확인 가능합니다.

 

GitHub - teiresias22/ImageSlider: CollectionView를 활용한 이미지 슬라이더

CollectionView를 활용한 이미지 슬라이더. Contribute to teiresias22/ImageSlider development by creating an account on GitHub.

github.com


이미지 슬라이드는 자주 사용되기 때문에 만들어봐야지 싶었는데 이번 기회에 만들어 보았다.  생각만큼은 어렵지 않았지만 이미지를 3개 세트로 구성해서 가운데서 돌려주는 방식을 하는것이 조금 까다로웠다. 이제 다음번은 카카오맵을 연결하는 내용을 포스팅 할 예정이다. (iOS 카카오맵 연동은 아직도 Object-C를 사용해서 브릿지를 통해 연결을 해주어야 했다....언제 업뎃 해주냐...ㅠㅠㅠ