iOS/Swift

[Swift] 배너 만들기(Make a Slide banner with Carousel)

HUISOO 2022. 9. 19. 17:40

이 포스트는 UICollectionView의 Carousel View로 배너를 만들기 위한 포스팅입니다 :)

 

Carousel은 우리말로 회전목마를 뜻합니다.

Carousel View는 일정한 형태를 유지하며 무한히 회전하는 View를 말하지만, 일정하게 Slide 되는 View를 칭하기도 합니다.

(무한히 회전하는 Carousel View를 만드는 방법은 차후에 포스팅하겠습니다.)

 

추가로 Timer를 이용하여 자동 스크롤이 되도록 하는 방법도 작성합니다.

 최종 수정일 - 22. 09. 20 AM 9:20



방법

 

1. UICollectionView 생성

@IBOutlet weak var collectionView: UICollectionView!

var cellSize: CGSize = .zero

func setupCollectionView() {

    cellSize = CGSize(width: collectionView.bounds.width, height: 100)
    
    collectionView.delegate = self
    collectionView.dataSource = self
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return 5
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return cellSize
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = UICollectionViewCell()
    
    cell.backgroundColor = .red
    
    return cell
}

 

2. 페이징 효과 넣기

func setupCollectionView() {

	// ...
    
    // collectionView.isPagingEnabled = true
    // cellSize의 width가 collectionView의 width와 다르다면 페이징이 어색한 경우가 생기기 때문에 해당 방법을 사용했다.
    // 만약 같다면 collectionView.isPagingEnabled = true 만 추가하고 그 외 코드는 불필요하다.
    
    collectionView.decelerationRate = .fast
    

}

// collectionView를 scroll하여 드래그가 끝났을때 다음 셀이 화면의 중앙에 오도록 하기
func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    let cellWidthIncludingSpacing: CGFloat = cellSize.width // + minimumLineSpacing

    let estimatedIndex = scrollView.contentOffset.x / cellWidthIncludingSpacing
    let index: Int
    if velocity.x > 0 {
        index = Int(ceil(estimatedIndex))
    } else if velocity.x < 0 {
        index = Int(floor(estimatedIndex))
    } else {
        index = Int(round(estimatedIndex))
    }

    targetContentOffset.pointee = CGPoint(x: (CGFloat(index) * cellWidthIncludingSpacing), y: 0)
}


3. 좌우 여백 추가하기

// cell 사이 간격
let minimumLineSpacing: CGFloat = 8

func setupCollectionView() {

    // cell의 양 옆에 여백이 생긴 만큼 width 값 조절
    cellSize = CGSize(width: collectionView.bounds.width - (minimumLineSpacing * 4), height: 100)

    // ...
    
    collectionView.contentInset = UIEdgeInsets(top: 0, left: minimumLineSpacing * 2, bottom: 0, right: minimumLineSpacing)
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
	return minimumLineSpacing
}

func scrollViewWillEndDragging(_ scrollView: UIScrollView, withVelocity velocity: CGPoint, targetContentOffset: UnsafeMutablePointer<CGPoint>) {
    let cellWidthIncludingSpacing: CGFloat = cellSize.width + minimumLineSpacing

	// ...

    targetContentOffset.pointee = CGPoint(x: (CGFloat(index) * cellWidthIncludingSpacing) - (minimumLineSpacing * 2), y: 0)
}

 


자동 스크롤 추가

1. Timer 생성

var timer: Timer = Timer()

func resetTimer() {
    timer.invalidate()
    timer = Timer.scheduledTimer(withTimeInterval: 3, repeats: true, block: { timer in
        let cellWidthIncludingSpacing: CGFloat = self.cellSize.width + self.minimumLineSpacing
        let estimatedIndex = self.collectionView.contentOffset.x / cellWidthIncludingSpacing
        let index = Int(round(estimatedIndex))

        let next = index + 1 == self.data.count ? 0 : index + 1

        if self.data.count == 0 { return }

        self.collectionView.scrollToItem(at: IndexPath(item: next, section: 0), at: .centeredHorizontally, animated: true)
    })
}

func setupCollectionView() {

	//...
    
    // 최초 타이머 등록
    resetTimer()
}

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

	// ...
    
    // 직접 스크롤하면 타이머를 초기화한다.
    resetTimer()
}