본문 바로가기
iOS/설명

[iOS] UICollectionView로 Carousel Banner만들기 (feat. Android ViewPager)

by Sky Titan 2021. 1. 9.
728x90

UICollectionView로 자동 Paging 배너 만들기

안드로이드에서는 다음과 같은 Paging 배너 효과를 구현하기 위해선 ViewPager를 활용해야 한다. ios에서는 ViewPager처럼 Paging에만 특화된 뷰는 PagingViewController가 있는데 이건 커스텀이 힘들어 보이고 대부분 CollectionView의 범용성을 활용한다.

 

Paging 배너 구현

  1. section의 개수는 1개로 지정한다.
  2. cell의 크기를 CollectionView와 동일하게 맞춰준다.
  3. cell사이와 section사이의 여백을 없앤다.

여기까지 하게 된다면 수동으로 스크롤이 가능한 배너가 만들어진다. 추가적으로 여기에 마치 배달의 민족 같은 앱에서 볼 수 있는 자동 스크롤 기능까지 넣고자 한다면 아래와 같이 하면 된다.

 

 

자동 스크롤링 기능

  1. DispatchQueue를 이용해서 비동기적으로 무한 루프 안에 주기적으로 collectionView.scrollToItem() 메서드를 호출한다.
  2. UIScrollViewDelegate를 채택 후 scrollViewDidEndDecelerating 메서드를 구현해서 사람이 직접 스크롤을 했을 때 현재 scroll 된 page의 index를 인식할 수 있도록 해준다.
//
//  ViewController.swift
//  Practice
//
//  Created by jupark136 on 2020/12/14.
//

import UIKit
import Alamofire

class ViewController: UIViewController {
  
    var currentPage: Int = 0
    
    @IBOutlet weak var collectionView: UICollectionView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        collectionView.decelerationRate = .fast
        collectionView.dataSource = self
        collectionView.delegate = self
        collectionView.isPagingEnabled = true
        
        startAutoScroll()
        
    }
    
    func startAutoScroll() {
        //전체 cell 개수
        let totalCellCount = collectionView.numberOfItems(inSection: 0)
        
        DispatchQueue.global(qos: .default).async {
            
            while true
            {
                //2초에 한 번씩 paging
                sleep(2)
                
                DispatchQueue.main.async {
                    self.collectionView.scrollToItem(at: IndexPath(item: self.currentPage, section: 0), at: .right, animated: true)
                    
                    //다시 처음으로
                    if self.currentPage == totalCellCount - 1 {
                        self.currentPage = 0
                    }
                    else {
                        self.currentPage += 1
                    }
                }
            }
            
        }
    }
}

extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{
    
    //총 page 개수
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        3
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "\(TestCell.self)", for: indexPath) as? TestCell else {
            fatalError("cell not")
        }
        
        cell.label.text = "\(indexPath.row)"
    
        return cell
    }
    
    func numberOfSections(in collectionView: UICollectionView) -> Int
    {
        1
    }
    
    //cell과 collectionview의 크기를 일치
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        CGSize.init(width: collectionView.bounds.width, height: collectionView.bounds.height)
    }
    
    //section 내부 cell간의 공간을 제거
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        0
    }
    
    //section 사이의 공간을 제거
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        0
    }
}

extension ViewController: UIScrollViewDelegate {
    
    //수동으로 넘을 때 page를 인식
    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
        let x = scrollView.contentOffset.x
        let w = scrollView.bounds.size.width
        currentPage = Int(ceil(x/w))
        print(currentPage)
    }

}
728x90

댓글