본문 바로가기

iOS

[iOS/Swift5] 스토리보드 없이 횡스크롤 UICollectionView 만들기

횡스크롤이 가능한 UICollectionView를 스토리 보드 없이 만들어봅니다.
스토리 보드 없이 SnapKit, Than 라이브러리를 사용해서 뷰를 그릴 예정입니다.

MainView.swift

뷰에 관한 파일을 먼저 정의합니다.

class MainView: UIView {
    
    let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()).then {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        
        $0.backgroundColor = .white
        $0.contentInset = UIEdgeInsets.init(top: 0, left: 20, bottom: 0, right: 0)
        $0.showsHorizontalScrollIndicator = false
        $0.collectionViewLayout = layout
    }
    
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
        bindConstraints()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setup()
        bindConstraints()
    }
    
    func setup() {
        backgroundColor = .white
        addSubview(collectionView)
    }
    
    func bindConstraints() {
        collectionView.snp.makeConstraints { (make) in
            make.left.right.equalToSuperview()
            make.centerY.equalToSuperview()
            make.height.equalTo(200)
        }
    }
}
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout()).then {
    let layout = UICollectionViewFlowLayout()
    layout.scrollDirection = .horizontal
        
    $0.backgroundColor = .white
    $0.contentInset = UIEdgeInsets.init(top: 0, left: 20, bottom: 0, right: 0)
    $0.showsHorizontalScrollIndicator = false
    $0.collectionViewLayout = layout
}

UICollectionView는 초기화할 당시에 collectionViewLayout 인자를 포함해서 초기화 시켜줘야합니다. 컴파일 오류는 나지 않지만 런타임에서 에러가 발생합니다. 따라서 인자로 일단은 넣어놓고 내부에서 다시 정의를 해주는 식으로 진행하였습니다 ㅠㅠ
횡스크롤을 설정하기 위하여 UICollectionViewFlowLayout 를 다시 정의한뒤 속성을 지정해주고 collectionView에 다시 설정해줍니다.
contentInset속성은 콜렉션뷰가 시작하는데 초기 padding값을 설정해주는 속성입니다.

 

MainCell.swift

import UIKit

class MainCell: UICollectionViewCell {
    
    static let registerId = "\(MainCell.self)"
    
    let main = UIView().then {
        $0.backgroundColor = .red
    }
    
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setup()
        bindConstraints()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setup()
        bindConstraints()
    }
    
    private func setup() {
        backgroundColor = .red
        addSubview(main)
    }
    
    private func bindConstraints() {
        main.snp.makeConstraints { (make) in
            make.edges.equalTo(0)
        }
    }
}

콜렉션뷰 안에 들어갈 셀을 정의해줍니다. 셀에는 색깔이 있는 뷰 하나만 그려서 넣었습니다.

ViewCollection.swift

import UIKit

class ViewController: UIViewController {
    
    private lazy var mainView = MainView.init(frame: self.view.frame)

    static func instance() -> ViewController {
        return ViewController.init(nibName: nil, bundle: nil)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        view = mainView
        setupCollectionView()
    }
    
    private func setupCollectionView() {
        mainView.collectionView.delegate = self
        mainView.collectionView.dataSource = self
        mainView.collectionView.register(MainCell.self, forCellWithReuseIdentifier: MainCell.registerId)
    }
}

extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 5
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MainCell.registerId, for: indexPath) as? MainCell else {
            return UICollectionViewCell()
        }
        
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize.init(width: 100, height: 100)
    }
    
}

private func setupCollectionView() {
    mainView.collectionView.delegate = self
    mainView.collectionView.dataSource = self
    mainView.collectionView.register(MainCell.self, forCellWithReuseIdentifier: MainCell.registerId)
}

콜렉션뷰를 설정하기 위해선 delegate, dataSource를 정의하고 cell을 등록해줘야합니다.
delegate는 터치 이벤트를 정의하기 위해 사용됩니다. 선택을 하지 않는거라면 굳이 필요하진 않습니다.
datasource는 콜렉션 뷰 안에 들어가는 데이터를 정의하기 위해 사용됩니다. 
셀을 등록할때에는 register함수를 사용하고 어떤 셀인지, 셀 id와 함께 정의해줍니다.

extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 5
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: MainCell.registerId, for: indexPath) as? MainCell else {
            return UICollectionViewCell()
        }
        
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize.init(width: 100, height: 100)
    }
}

extension으로 UICollectionViewDelegate, UICollectionViewDataSource를 구현해줍니다.


func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
하나의 섹션안에 몇개의 아이템이 들어가는지 정의해줍시다. 여기에서는 5개만 보여주기 때문에 5라고 정의해줍니다.

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
콜렉션 뷰 안에 들어갈 cell을 정의해주면 됩니다. 이 예제의 경우에는 MainCell을 사용하기 때문에 MainCell을 반환해주면 됩니다.

이 두개의 함수만 정의하면 정상적으로 동작합니다. 예제 아래에 적혀있는 추가적인 함수는 셀 크기를 정의하는 함수입니다. 
UICollectionViewDelegateFlowLayout안에 들어있는 함수입니다.