티스토리 뷰

iOS

iOS) UICollectionView Programmatically

Ekko0701 2022. 7. 20. 14:18

위와 같은 CollectionView를 Storyboard 없이 코드를 사용해서 구현해보자.

 

Autolayout은 SnapKit을 사용했다.

 

 

 

1. UICollectionViewCell 생성

먼저 CollectionView에 사용할 UICollectionViewCell을 만들었다.

CollectionViewCell.swift

//
//  CollectionViewCell.swift
//  CollectionView_Programmatically_Tutorial

import UIKit
import SnapKit

class CollectionViewCell: UICollectionViewCell {
    
    // Reuse Identifier
    static let cellId = "CollectionCellId"
    
    // Set Cell Elements
    let foodImage: UIImageView = {
        let image = UIImageView()
        image.image = UIImage(named: "image1")
        image.contentMode = .scaleAspectFit
        return image
    }()
    
    let foodLabel: UILabel = {
        let label = UILabel()
        label.font = UIFont.systemFont(ofSize: 16)
        label.text = "Goulash"
        label.textAlignment = .center
        return label
    }()
    
    // Init
    override init(frame: CGRect) {
        super.init(frame: .zero)
        setUpCell()
        setUpLayout()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

extension CollectionViewCell {
    func setUpCell() {
        addSubview(foodImage)
        addSubview(foodLabel)
    }
    
    func setUpLayout() {
        
        // Autolayout with SnapKit
        
        foodImage.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(16)
            make.leading.equalToSuperview().offset(32)
            make.bottom.equalToSuperview().offset(-32)
            make.trailing.equalToSuperview().offset(-32)
        }
        foodLabel.snp.makeConstraints { make in
            make.top.equalTo(foodImage.snp.bottom).offset(-16)
            make.leading.trailing.equalTo(foodImage)
            
        }
    }
}

 

CollectionViewCell에 UIImageView와 UILabel을 각각 foodImage, foodLabel이라는 이름으로 생성해주었다.

 

setUpCell()에서는 위에서 foodImage와 foodLabel을 SubView로 추가.

 

setUpLayout()에서는 SnapKit을 이용해 layout을 설정해 주었다.

 

 

다음으로 ViewController.swift에서 collectionView를 만든 후 그 안에 collectionViewCell을 넣어보자.

 

 

2.  Data 배열 생성 &  Asset에 Image 추가

ViewController.swift

 

 데이터 배열을 하나 만들어 주었다.

var data = ["Goulash", "Maple Syrup", "Nasi Goreng", "Paella", "Pasta", "Spring rolls",
"Goulash", "Maple Syrup", "Nasi Goreng", "Paella", "Pasta", "Spring rolls",
"Goulash", "Maple Syrup", "Nasi Goreng", "Paella", "Pasta", "Spring rolls"]

 

Assets 이미지도 추가해 주었다.

 

3. UICollectionView 생성

collectionView 생성

var collectionView: UICollectionView!

 

 

 

- setUpCollectionView()

collectionView에 대한 설정을 해주자.

func setUpCollectionView() {
        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        layout.scrollDirection = .horizontal // Scroll 방향 설정
        
        collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        
        // Delegate, DataSource, Register Cell
        collectionView.delegate = self
        collectionView.dataSource = self
        collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: CollectionViewCell.cellId)
        
        //Background Color
        collectionView.backgroundColor = .blue
    }

 

CollectionView는 TableView와 다르게 layout을 추가해 주어야 한다. 그렇지 않을 경우 에러가 발생한다.

layout이라는 UICollectionViewFlowLayout 객체를 생성하고 필요한 속성을 추가해주자.

 

위에서는 sectionInset을 전부 0으로 해서 collectionView와 section이 딱 맞게 해 줬고

scrollDirection을 .horizontal로 변경해 주었다.

 

추가로 cell의 size와 cell 간의 간격 등을 조절할 수 있다. 공식 홈페이지를 참고하자.

https://developer.apple.com/documentation/uikit/uicollectionviewflowlayout

 

Apple Developer Documentation

 

developer.apple.com

 

collectionView에 frame과 만들어둔 layout을 추가해주자.

collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)

 

setUpCollectionView()에서 추가로 UICollectionViewDelegate, UICollectionViewDataSource 프로토콜을 채택해 주었고 

위에서 미리 만들어 두었던 CollectionViewCell을 등록해 주었다.

 

 

-setUpView() & setUpLayout()

이제 만들었던 collectionView를 Subview로 추가해주고

Snapkit을 이용해 layout을 추가해주었다.

func setUpView() {
        view.addSubview(collectionView)
    }
    

 func setUpLayout() {
        collectionView.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(40)
            make.leading.trailing.equalToSuperview()
            make.height.equalTo(160)
        }
    }

 

setUpCollectionView(), setUpView(), setUpLayout() 모두 viewDidLoad()에서 실행해 주는 것을 잊지 말자.

override func viewDidLoad() {
        super.viewDidLoad()
        
        setUpCollectionView()
        setUpView()
        setUpLayout()
    }

 

 

4. UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewFlowLayout 

extension ViewController: UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        print("Did Selected Item At : \(indexPath.row)")
    }
}

didSelectItemAt 메소드를 이용해 cell을 선택하면 몇 번째 cell이 선택됐는지 print 하도록 했다.

 

extension ViewController: UICollectionViewDataSource {
    // Section의 Item 개수 설정
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return data.count
    }
    
    // cell 설정
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CollectionViewCell.cellId, for: indexPath) as! CollectionViewCell
        cell.backgroundColor = .systemGreen
        
        let imageNumber: Int = indexPath.row % 6 + 1
        
        cell.foodImage.image = UIImage(named: "image\(imageNumber)")
        cell.foodLabel.text = data[indexPath.row]
        
        return cell
    }
}

 

UICollectionViewDataSource를 채택하면 numberOfItemInSection, cellForItemAt 이 두 메서드는 필수로 구현해야 한다.

 

numberOfItemInSection은 아이템의 개수, cellForItemAt 은 cell을 생성한다.

 

extension ViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: 160, height: 200)
    }
}

 

UICollectionViewDelegateFlowLayout에서는 아이템의 사이즈를 설정해 주었다.

 

위의 collectionView를 생성할 때 추가했던 UICollectionViewFlowLayout 객체인 layout에서도 item의 사이즈나 간격을 설정할 수 있지만 UICollectionViewDelegateFlowLayout에서도 설정 가능하다.

 

 

ViewController.swift 전체 코드

//
//  ViewController.swift
//  CollectionView_Programmatically_Tutorial


import UIKit
import SnapKit

class ViewController: UIViewController {

    var collectionView: UICollectionView!
    var data = ["Goulash", "Maple Syrup", "Nasi Goreng", "Paella", "Pasta", "Spring rolls","Goulash", "Maple Syrup", "Nasi Goreng", "Paella", "Pasta", "Spring rolls","Goulash", "Maple Syrup", "Nasi Goreng", "Paella", "Pasta", "Spring rolls"]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        setUpCollectionView()
        setUpView()
        setUpLayout()
    }
}

extension ViewController {
    
    func setUpCollectionView() {
        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        layout.scrollDirection = .horizontal // Scroll 방향 설정
        
        collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        
        // Delegate, DataSource, Register Cell
        collectionView.delegate = self
        collectionView.dataSource = self
        collectionView.register(CollectionViewCell.self, forCellWithReuseIdentifier: CollectionViewCell.cellId)
        
        //Background Color
        collectionView.backgroundColor = .blue
    }
    
    func setUpView() {
        view.addSubview(collectionView)
    }
    
    func setUpLayout() {
        collectionView.snp.makeConstraints { make in
            make.top.equalToSuperview().offset(40)
            make.leading.trailing.equalToSuperview()
            make.height.equalTo(160)
        }
    }
}

extension ViewController: UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        print("Did Selected Item At : \(indexPath.row)")
    }
}

extension ViewController: UICollectionViewDataSource {
    // Section의 Item 개수 설정
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return data.count
    }
    
    // cell 설정
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CollectionViewCell.cellId, for: indexPath) as! CollectionViewCell
        cell.backgroundColor = .systemGreen
        
        let imageNumber: Int = indexPath.row % 6 + 1
        
        cell.foodImage.image = UIImage(named: "image\(imageNumber)")
        cell.foodLabel.text = data[indexPath.row]
        
        return cell
    }
}

extension ViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: 160, height: 200)
    }
}

 

실행해보면 다음과 같이 잘 작동한다.

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/07   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31
글 보관함