[UIKit] UICollectionView: Custom CollectionViewCell

Junyoung Park·2022년 10월 28일
0

UIKit

목록 보기
59/142
post-thumbnail

Swift 5: Custom CollectionView Cells (Programmatically) Xcode 11 - 2020 iOS

UICollectionView: Custom CollectionViewCell

구현 목표

  • 커스텀 컬렉션 셀 구현을 통해 컬렉션 뷰 내의 레이아웃 및 UI 표현

구현 태스크

  • 커스텀 셀 구현
  • 패딩, 프레임 베이스 레이아웃

핵심 코드

    override func layoutSubviews() {
        super.layoutSubviews()
        let height = contentView.frame.size.height
        let width = contentView.frame.size.width
        label.frame = CGRect(x: 5, y: height - 50, width: width - 10, height: 50)
        imageView.frame = CGRect(x: 5, y: 0, width: width - 10, height: height - 50)
    }
  • 컨텐츠 뷰의 프레임을 상수화한 뒤 layoutSubviews() 함수를 오버라이드할 때 적용

소스 코드

import UIKit

class CollectionViewController: UIViewController {
    private let collectionView: UICollectionView = {
        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .vertical
        layout.minimumLineSpacing = 1
        layout.minimumInteritemSpacing = 1
        let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
        collectionView.alwaysBounceVertical = true
        collectionView.register(CustomCollectionViewCell.self, forCellWithReuseIdentifier: CustomCollectionViewCell.identifier)
        return collectionView
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        setUI()
    }
    
    override func viewDidLayoutSubviews() {
        super.viewDidLayoutSubviews()
        collectionView.frame = view.bounds
    }
    
    private func setUI() {
        view.backgroundColor = .systemBackground
        view.addSubview(collectionView)
        collectionView.delegate = self
        collectionView.dataSource = self
    }
}

extension CollectionViewController: UICollectionViewDelegate {
    
}

extension CollectionViewController: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CustomCollectionViewCell.identifier, for: indexPath) as? CustomCollectionViewCell else {
            return UICollectionViewCell()
        }
        if let number = (1...10).randomElement() {
            let text = "random animal #\(number)"
            let imageName = "animal_\(number)"
            let model = ImageModel(text: text, imageName: imageName)
            cell.configure(with: model)
        }
        return cell
    }
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 100
    }
}

extension CollectionViewController: UICollectionViewDelegateFlowLayout {
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let width = view.frame.size.width / 3
        return CGSize(width: width - 4, height: width - 4)
    }
}
  • 100 개의 셀을 로드하는 컬렉션 뷰 구현
  • 이미지를 렌더링하는 configure 함수 적용 시 커스텀 셀 사용을 위한 guard let 바인딩 적용
import UIKit

class CustomCollectionViewCell: UICollectionViewCell {
    static let identifier = "CustomCollectionViewCell"
    private let imageView: UIImageView = {
        let imageView = UIImageView()
        imageView.clipsToBounds = true
        return imageView
    }()
    private let label: UILabel = {
        let label = UILabel()
        label.textColor = .label
        label.font = .systemFont(ofSize: 12, weight: .bold)
        label.numberOfLines = 0
        label.textAlignment = .center
        return label
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setUI()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        let height = contentView.frame.size.height
        let width = contentView.frame.size.width
        label.frame = CGRect(x: 5, y: height - 50, width: width - 10, height: 50)
        imageView.frame = CGRect(x: 5, y: 0, width: width - 10, height: height - 50)
    }
    
    override func prepareForReuse() {
        super.prepareForReuse()
        imageView.image = nil
        label.text = nil
    }
    
    private func setUI() {
        contentView.backgroundColor = .systemPink
        contentView.addSubview(label)
        contentView.addSubview(imageView)
    }
    
    func configure(with model: ImageModel) {
        label.text = model.text
        imageView.image = UIImage(named: model.imageName)
    }
}
  • prepareForeReuse() 함수 오버라이드 시 셀의 공통적으로 사용되는 부분을 제외한 나머지는 nil로 줄 수 있음
import Foundation

struct ImageModel {
    let text: String
    let imageName: String
}

구현 화면

profile
JUST DO IT

0개의 댓글