iOS) Coursel CollectionView 코드로 구현해보기
이번에는 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 번 아이템이 보여지게 하고,
실제 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
}
}
}