iOS

iOS) Coursel CollectionView 코드로 구현해보기

Jimmy Youn 2022. 3. 18. 12:44

이번에는 collectionView 를 활용하여 이벤트 배너처럼 구현해 보았는데 끝이 없이 계속 돌아가도록 해보았다. 

이런걸 Coursel CollectionView 라고 하는데 여기서 Coursel 은 '회전목마' 라는 뜻으로 끝이 없이 계속 돌아간다는 의미이다. 

 

어떻게 collectionView 를 이용하여 무한히 도는 것을 구현할지 생각해본 결과 간단하게 생각해보면 보여지는 데이터가 있다면 그 데이터의 마지막 항목에서 오른쪽으로 스크롤시 다음 항목을 다시 첫번째로 또는 그 데이터의 처음 항목에서 왼쪽으로 스크롤시 다음 항목을 다시 마지막번째로 강제 이동을 시킨다는 것이다. 

 

다시 한번 쉽게 설명을 하자면 보여주고 싶은 이벤트 배너 아이템이 1, 2, 3 이 있다고 가정을 해보자. 

총 데이터는 실제 데이터 앞에 가짜 데이터 1', 2', 3' 를 두고, 실제 데이터 뒤에 가짜 데이터 1'', 2'', 3'' 를 둔다. 

그러면 총 데이터 배열은  -> 1', 2', 3', 1 , 2, 3, 1'', 2'', 3''  처럼 될것이다. 

여기서 실제 3 번 아이템에서 가짜 1'' 아이템으로 스크롤을 할때 진짜 번 아이템이 보여지게 하고,

실제 1 번 아이템에서 가짜 3' 아이템으로 스크롤을 할때 진짜 3 번 아이템이 보여지게 하면 collectionView 가 무한히 도는것처럼 느껴지게 할 수 있다. 

 

여기서는 간단하게 collectionView backgroundColor 를 다르게 줘서 구현을 해보았다. 전체 코드는 깃헙 에서 확인 가능하다.

 

1. Property 속성 정의하기 

import UIKit

class ViewController: UIViewController {
  
  //MARK: - Properties
  
  // collectionView 정의 
  private lazy var carouselCollectionView : UICollectionView = {
    let collectionViewLayout = UICollectionViewFlowLayout()
    collectionViewLayout.scrollDirection = .horizontal
    let collectionView = UICollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
    collectionView.backgroundColor = .white
    collectionView.delegate = self
    collectionView.dataSource = self
    collectionView.isPagingEnabled = true
    collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "cell")
    return collectionView
  }()
  
  // collectionView 에 보여질 데이터 정의 (여기서는 background Color)
  private let colorData : [UIColor] = [.yellow, .blue, .red, .brown, .purple]
  
  // 앞에서 말한 가짜 데이터 + 진짜 데이터 + 가짜 데이터를 합친 데이터
  private lazy var increasedColorData :  [UIColor] = {
    colorData + colorData + colorData
  }()
  
  // 실제 데이터 count 값 
  private var originalColorDataCount : Int {
    colorData.count
  }

  // 실제 데이터의 마지막에서 오른쪽으로 넘어가는지 판별하는 Bool 값
  private var scrollToEnd : Bool = false
  
  // 실제 데이터의 처음에서 왼쪽으로 넘어가는지 판별하는 Bool 값
  private var scrollToBegin : Bool = false
  
  }

 

2. collectionView 기본 세팅해주기 

  ...
  
  //MARK: - LifeCycle
  override func viewDidLoad() {
    super.viewDidLoad()
    configureUI()
  }
  
  //MARK: - Functions
  private func configureUI() {
    view.backgroundColor = .white
    view.addSubview(carouselCollectionView)
    
    carouselCollectionView.translatesAutoresizingMaskIntoConstraints = false
    NSLayoutConstraint.activate([
        carouselCollectionView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
        carouselCollectionView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
        carouselCollectionView.widthAnchor.constraint(equalTo: view.widthAnchor),
        carouselCollectionView.heightAnchor.constraint(equalToConstant: 400)
    ])
  }
}

  //MARK: - UICollectionViewDelegateFlowLayout
extension ViewController : UICollectionViewDelegateFlowLayout {
  func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
      return CGSize(width: view.bounds.width, height: 400)
  }
  
  func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
      return .zero
  }
}
  
  //MARK: - UICollectionViewDataSource
extension ViewController : UICollectionViewDataSource {
  func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return increasedColorData.count
  }
  
  func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath)
    cell.backgroundColor = increasedColorData[indexPath.item]
    return cell
  }
}

 이렇게 하면 기본 15개 아이템의 collectionView 가 만들어진다. 

 

3. 이제 UIScrollViewDelegate 메소드중 scrollViewWillEndDragging 과 scrollViewDidEndDecelerating 을 이용해서 coursel 이펙트를 준다. 

  //MARK: - UIScrollViewDelegate
extension ViewController: UIScrollViewDelegate {
    func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
      
        let beginOffset = carouselCollectionView.frame.width * CGFloat(originalColorDataCount) // 15개 중에서 5번째 실제 데이터가 있는곳
        let endOffset = carouselCollectionView.frame.width * CGFloat(originalColorDataCount * 2 - 1) // 15개 중에서 10번째 실제 데이터가 있는곳
        
        if scrollView.contentOffset.x < beginOffset && velocity.x < .zero { // 처음 -> 마지막으로 드래그 했을때
            scrollToEnd = true
        } else if scrollView.contentOffset.x > endOffset && velocity.x > .zero { // 마지막 -> 처음으로 드래그 했을때
            scrollToBegin = true
        }
    }
    
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        if scrollToBegin {
        // 강제로 실제 데이터의 첫번째 아이템으로 이동시키기
            carouselCollectionView.scrollToItem(at: IndexPath(item: originalColorDataCount, section: .zero),
                                                at: .centeredHorizontally,
                                                animated: false)
            scrollToBegin.toggle()
            return
        }
      
        if scrollToEnd {
        // 강제로 실제 데이터의 마지막 아이템으로 이동시키기
            carouselCollectionView.scrollToItem(at: IndexPath(item: originalColorDataCount * 2 - 1 , section: .zero),
                                                at: .centeredHorizontally,
                                                animated: false)
            scrollToEnd.toggle()
            return
        }
    }
}

 

참고 : https://velog.io/@dvhuni/Carousel-CollectionView-만들어보기