How to create UICollectionViewCell programmaticall

2019-02-01 08:45发布

问题:

I'm trying to create UICollectionView programatically. I need to add labels inside the cells, so I Created CollectionViewCell class.

This is the class:

import UIKit

class MyCollectionViewCell: UICollectionViewCell {

    override init(frame: CGRect) {
        super.init(frame: frame)
    }

    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}

And this is the collectionView implementation class:

import UIKit

class TwoViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UICollectionViewDelegate {

    let leftAndRightPaddings: CGFloat = 80.0
    let numberOfItemsPerRow: CGFloat = 7.0
    let screenSize: CGRect = UIScreen.mainScreen().bounds
    private let cellReuseIdentifier = "collectionCell"
    var items = ["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"]

    override func viewDidLoad() {
        super.viewDidLoad()
        let flowLayout = UICollectionViewFlowLayout()
        let collectionView = UICollectionView(frame: self.view.bounds, collectionViewLayout: flowLayout)
        collectionView.registerClass(MyCollectionViewCell.self, forCellWithReuseIdentifier: cellReuseIdentifier)

        collectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "collectionCell")
        collectionView.delegate = self
        collectionView.dataSource = self
        collectionView.backgroundColor = UIColor.cyanColor()

        self.view.addSubview(collectionView)
    }

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
    {
        return self.items.count
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
    {
        let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellReuseIdentifier, forIndexPath: indexPath) as! MyCollectionViewCell
        cell.backgroundColor = UIColor.greenColor()
        return cell
    }

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize
    {
        let width = (screenSize.width-leftAndRightPaddings)/numberOfItemsPerRow
        return CGSizeMake(width, width)
    }

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets
    {
        return UIEdgeInsets(top: 20, left: 8, bottom: 5, right: 8)
    }

}

The error happens when the cell produced:

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell
{
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellReuseIdentifier, forIndexPath: indexPath) as! MyCollectionViewCell

The error is:

Could not cast value of type 'UICollectionViewCell' (0x1033cc820) to 'CollectionViewProgramatically.MyCollectionViewCell' (0x1015a4f88).

回答1:

Your problem lies here. In your viewDidLoad(), you're registering your collectionView cell twice. You are registering the collectionview's cell to your custom cell class in the first line and then in the second line you are registering it to the class UICollectionViewCell.

 collectionView.registerClass(MyCollectionViewCell.self, forCellWithReuseIdentifier: cellReuseIdentifier)
 collectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "collectionCell")

Just remove the second line and your code should work.



回答2:

Try to copy and paste this code into your xcode, it should work

//
//  HomeVIewController.swift
//  Photolancer
//
//  Created by Lee SangJoon  on 9/8/16.
//  Copyright © 2016 Givnite. All rights reserved.
//

import UIKit


class HomeViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {



    var collectionview: UICollectionView!
    var cellId = "Cell"

    override func viewDidLoad() {
        super.viewDidLoad()

        // Create an instance of UICollectionViewFlowLayout since you cant
        // Initialize UICollectionView without a layout
        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        layout.itemSize = CGSize(width: view.frame.width, height: 700)

        collectionview = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
        collectionview.dataSource = self
        collectionview.delegate = self
        collectionview.registerClass(FreelancerCell.self, forCellWithReuseIdentifier: cellId)
        collectionview.showsVerticalScrollIndicator = false
        collectionview.backgroundColor = UIColor.whiteColor()
        self.view.addSubview(collectionview)

    }

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


    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
        let cell = collectionview.dequeueReusableCellWithReuseIdentifier(cellId, forIndexPath: indexPath) as! FreelancerCell
        return cell
    }


}








class FreelancerCell: UICollectionViewCell {


    let profileImageButton: UIButton = {
        let button = UIButton()
        button.backgroundColor = UIColor.whiteColor()
        button.layer.cornerRadius = 18
        button.clipsToBounds = true
        button.setImage(UIImage(named: "Profile"), forState: .Normal)

        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()


    let nameLabel: UILabel = {
        let label = UILabel()
        label.font = UIFont.systemFontOfSize(14)
        label.textColor = UIColor.darkGrayColor()
        label.text = "Bob Lee"
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()


    let distanceLabel: UILabel = {
        let label = UILabel()
        label.textColor = UIColor.lightGrayColor()
        label.font = UIFont.systemFontOfSize(14)
        label.text = "30000 miles"
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    let pricePerHourLabel: UILabel = {
        let label = UILabel()
        label.textColor = UIColor.darkGrayColor()
        label.font = UIFont.systemFontOfSize(14)
        label.text = "$40/hour"
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()



    let ratingLabel: UILabel = {
        let label = UILabel()
        label.textColor = UIColor.lightGrayColor()
        label.font = UIFont.systemFontOfSize(14)
        label.text = "4.9+"
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()


    let showCaseImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.backgroundColor = UIColor.whiteColor()
        imageView.image = UIImage(named: "Profile")
        imageView.translatesAutoresizingMaskIntoConstraints = false
        return imageView
    }()


    let likesLabel: UILabel = {
        let label = UILabel()
        label.textColor = UIColor.lightGrayColor()
        label.font = UIFont.systemFontOfSize(14)
        label.text = "424 likes"
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()


    let topSeparatorView: UIView = {
        let view = UIView()
        view.backgroundColor = UIColor.darkGrayColor()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    let bottomSeparatorView: UIView = {
        let view = UIView()
        view.backgroundColor = UIColor.darkGrayColor()
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()


    let likeButton: UIButton = {
        let button = UIButton()
        button.setTitle("Like", forState: .Normal)
        button.titleLabel?.font = UIFont.systemFontOfSize(18)
        button.setTitleColor(UIColor.darkGrayColor(), forState: .Normal)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()

    let hireButton: UIButton = {
        let button = UIButton()
        button.setTitle("Hire", forState: .Normal)
        button.titleLabel?.font = UIFont.systemFontOfSize(18)
        button.setTitleColor(UIColor.darkGrayColor(), forState: .Normal)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()


    let messageButton: UIButton = {
        let button = UIButton()
        button.setTitle("Message", forState: .Normal)
        button.titleLabel?.font = UIFont.systemFontOfSize(18)
        button.setTitleColor(UIColor.darkGrayColor(), forState: .Normal)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()



    let stackView: UIStackView = {
        let sv = UIStackView()
        sv.axis  = UILayoutConstraintAxis.Horizontal
        sv.alignment = UIStackViewAlignment.Center
        sv.distribution = UIStackViewDistribution.FillEqually
        sv.translatesAutoresizingMaskIntoConstraints = false;
        return sv
    }()




    override init(frame: CGRect) {
        super.init(frame: frame)

        addViews()
    }




    func addViews(){
        backgroundColor = UIColor.blackColor()

        addSubview(profileImageButton)
        addSubview(nameLabel)
        addSubview(distanceLabel)
        addSubview(pricePerHourLabel)
        addSubview(ratingLabel)
        addSubview(showCaseImageView)
        addSubview(likesLabel)

        addSubview(topSeparatorView)
        addSubview(bottomSeparatorView)

        // Stack View
        addSubview(likeButton)
        addSubview(messageButton)
        addSubview(hireButton)
        addSubview(stackView)


        profileImageButton.leftAnchor.constraintEqualToAnchor(leftAnchor, constant: 5).active = true
        profileImageButton.topAnchor.constraintEqualToAnchor(topAnchor, constant: 10).active = true
        profileImageButton.heightAnchor.constraintEqualToConstant(36).active = true
        profileImageButton.widthAnchor.constraintEqualToConstant(36).active = true

        nameLabel.leftAnchor.constraintEqualToAnchor(profileImageButton.rightAnchor, constant: 5).active = true
        nameLabel.centerYAnchor.constraintEqualToAnchor(profileImageButton.centerYAnchor, constant: -8).active = true
        nameLabel.rightAnchor.constraintEqualToAnchor(pricePerHourLabel.leftAnchor).active = true

        distanceLabel.leftAnchor.constraintEqualToAnchor(nameLabel.leftAnchor).active = true
        distanceLabel.centerYAnchor.constraintEqualToAnchor(profileImageButton.centerYAnchor, constant: 8).active = true
        distanceLabel.widthAnchor.constraintEqualToConstant(300)

        pricePerHourLabel.rightAnchor.constraintEqualToAnchor(rightAnchor, constant: -10).active = true
        pricePerHourLabel.centerYAnchor.constraintEqualToAnchor(nameLabel.centerYAnchor).active = true

        // Distance depeneded on the priceLabel and distance Label
        ratingLabel.rightAnchor.constraintEqualToAnchor(pricePerHourLabel.rightAnchor).active = true
        ratingLabel.centerYAnchor.constraintEqualToAnchor(distanceLabel.centerYAnchor).active = true

        showCaseImageView.topAnchor.constraintEqualToAnchor(profileImageButton.bottomAnchor, constant: 10).active = true
        showCaseImageView.widthAnchor.constraintEqualToAnchor(widthAnchor).active = true
        showCaseImageView.heightAnchor.constraintEqualToConstant(UIScreen.mainScreen().bounds.width - 20).active = true

        likesLabel.topAnchor.constraintEqualToAnchor(showCaseImageView.bottomAnchor, constant: 10).active = true
        likesLabel.leftAnchor.constraintEqualToAnchor(profileImageButton.leftAnchor).active = true

        topSeparatorView.topAnchor.constraintEqualToAnchor(likesLabel.bottomAnchor, constant: 10).active = true
        topSeparatorView.widthAnchor.constraintEqualToAnchor(widthAnchor).active = true
        topSeparatorView.heightAnchor.constraintEqualToConstant(0.5).active = true

        stackView.addArrangedSubview(likeButton)
        stackView.addArrangedSubview(hireButton)
        stackView.addArrangedSubview(messageButton)

        stackView.topAnchor.constraintEqualToAnchor(topSeparatorView.bottomAnchor, constant: 4).active = true
        stackView.widthAnchor.constraintEqualToAnchor(widthAnchor).active = true
        stackView.centerXAnchor.constraintEqualToAnchor(centerXAnchor).active = true

        bottomSeparatorView.topAnchor.constraintEqualToAnchor(stackView.bottomAnchor, constant: 4).active = true
        bottomSeparatorView.widthAnchor.constraintEqualToAnchor(widthAnchor).active = true
        bottomSeparatorView.heightAnchor.constraintEqualToConstant(0.5).active = true


    }



    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}


回答3:

I changed Bob Lee answer for swift 4

import UIKit


class noNibCollectionViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {



    var collectionview: UICollectionView!
    var cellId = "Cell"

    override func viewDidLoad() {
        super.viewDidLoad()

        // Create an instance of UICollectionViewFlowLayout since you cant
        // Initialize UICollectionView without a layout
        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
        layout.itemSize = CGSize(width: view.frame.width, height: 700)

        collectionview = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
        collectionview.dataSource = self
        collectionview.delegate = self
        collectionview.register(FreelancerCell.self, forCellWithReuseIdentifier: cellId)
        collectionview.showsVerticalScrollIndicator = false
        collectionview.backgroundColor = UIColor.white
        self.view.addSubview(collectionview)

    }

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


    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionview.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! FreelancerCell
        return cell
    }


}








class FreelancerCell: UICollectionViewCell {


    let profileImageButton: UIButton = {
        let button = UIButton()
        button.backgroundColor = UIColor.white
        button.layer.cornerRadius = 18
        button.clipsToBounds = true
        button.setImage(UIImage(named: "Profile"), for: .normal)

        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()


    let nameLabel: UILabel = {
        let label = UILabel()
        label.font = UIFont.systemFont(ofSize: 14)
        label.textColor = UIColor.darkGray
        label.text = "Bob Lee"
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()


    let distanceLabel: UILabel = {
        let label = UILabel()
        label.textColor = UIColor.lightGray
        label.font = UIFont.systemFont(ofSize: 14)
        label.text = "30000 miles"
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()

    let pricePerHourLabel: UILabel = {
        let label = UILabel()
        label.textColor = UIColor.darkGray
        label.font = UIFont.systemFont(ofSize: 14)
        label.text = "$40/hour"
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()



    let ratingLabel: UILabel = {
        let label = UILabel()
        label.textColor = UIColor.lightGray
        label.font = UIFont.systemFont(ofSize: 14)
        label.text = "4.9+"
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()


    let showCaseImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.backgroundColor = UIColor.white
        imageView.image = UIImage(named: "Profile")
        imageView.translatesAutoresizingMaskIntoConstraints = false
        return imageView
    }()


    let likesLabel: UILabel = {
        let label = UILabel()
        label.textColor = UIColor.lightGray
        label.font = UIFont.systemFont(ofSize: 14)
        label.text = "424 likes"
        label.translatesAutoresizingMaskIntoConstraints = false
        return label
    }()


    let topSeparatorView: UIView = {
        let view = UIView()
        view.backgroundColor = UIColor.darkGray
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()

    let bottomSeparatorView: UIView = {
        let view = UIView()
        view.backgroundColor = UIColor.darkGray
        view.translatesAutoresizingMaskIntoConstraints = false
        return view
    }()


    let likeButton: UIButton = {
        let button = UIButton()
        button.setTitle("Like", for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 18)
        button.setTitleColor(UIColor.darkGray, for: .normal)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()

    let hireButton: UIButton = {
        let button = UIButton()
        button.setTitle("Hire", for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 18)
        button.setTitleColor(UIColor.darkGray, for: .normal)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()


    let messageButton: UIButton = {
        let button = UIButton()
        button.setTitle("Message", for: .normal)
        button.titleLabel?.font = UIFont.systemFont(ofSize: 18)
        button.setTitleColor(UIColor.darkGray, for: .normal)
        button.translatesAutoresizingMaskIntoConstraints = false
        return button
    }()



    let stackView: UIStackView = {
        let sv = UIStackView()
        sv.axis  = UILayoutConstraintAxis.horizontal
        sv.alignment = UIStackViewAlignment.center
        sv.distribution = UIStackViewDistribution.fillEqually
        sv.translatesAutoresizingMaskIntoConstraints = false;
        return sv
    }()




    override init(frame: CGRect) {
        super.init(frame: frame)

        addViews()
    }




    func addViews(){
        backgroundColor = UIColor.black

        addSubview(profileImageButton)
        addSubview(nameLabel)
        addSubview(distanceLabel)
        addSubview(pricePerHourLabel)
        addSubview(ratingLabel)
        addSubview(showCaseImageView)
        addSubview(likesLabel)

        addSubview(topSeparatorView)
        addSubview(bottomSeparatorView)

        // Stack View
        addSubview(likeButton)
        addSubview(messageButton)
        addSubview(hireButton)
        addSubview(stackView)


        profileImageButton.leftAnchor.constraint(equalTo: leftAnchor, constant: 5).isActive = true
        profileImageButton.topAnchor.constraint(equalTo: topAnchor, constant: 10).isActive = true
        profileImageButton.heightAnchor.constraint(equalToConstant: 36).isActive = true
        profileImageButton.widthAnchor.constraint(equalToConstant: 36).isActive = true

        nameLabel.leftAnchor.constraint(equalTo: profileImageButton.rightAnchor, constant: 5).isActive = true
        nameLabel.centerYAnchor.constraint(equalTo: profileImageButton.centerYAnchor, constant: -8).isActive = true
        nameLabel.rightAnchor.constraint(equalTo: pricePerHourLabel.leftAnchor).isActive = true

        distanceLabel.leftAnchor.constraint(equalTo: nameLabel.leftAnchor).isActive = true
        distanceLabel.centerYAnchor.constraint(equalTo: profileImageButton.centerYAnchor, constant: 8).isActive = true
        distanceLabel.widthAnchor.constraint(equalToConstant: 300)

        pricePerHourLabel.rightAnchor.constraint(equalTo: rightAnchor, constant: -10).isActive = true
        pricePerHourLabel.centerYAnchor.constraint(equalTo: nameLabel.centerYAnchor).isActive = true

        // Distance depeneded on the priceLabel and distance Label
        ratingLabel.rightAnchor.constraint(equalTo: pricePerHourLabel.rightAnchor).isActive = true
        ratingLabel.centerYAnchor.constraint(equalTo: distanceLabel.centerYAnchor).isActive = true

        showCaseImageView.topAnchor.constraint(equalTo: profileImageButton.bottomAnchor, constant: 10).isActive = true
        showCaseImageView.widthAnchor.constraint(equalTo: widthAnchor).isActive = true
        showCaseImageView.heightAnchor.constraint(equalToConstant: UIScreen.main.bounds.width - 20).isActive = true

        likesLabel.topAnchor.constraint(equalTo: showCaseImageView.bottomAnchor, constant: 10).isActive = true
        likesLabel.leftAnchor.constraint(equalTo: profileImageButton.leftAnchor).isActive = true

        topSeparatorView.topAnchor.constraint(equalTo: likesLabel.bottomAnchor, constant: 10).isActive = true
        topSeparatorView.widthAnchor.constraint(equalTo: widthAnchor).isActive = true
        topSeparatorView.heightAnchor.constraint(equalToConstant: 0.5).isActive = true

        stackView.addArrangedSubview(likeButton)
        stackView.addArrangedSubview(hireButton)
        stackView.addArrangedSubview(messageButton)

        stackView.topAnchor.constraint(equalTo: topSeparatorView.bottomAnchor, constant: 4).isActive = true
        stackView.widthAnchor.constraint(equalTo: widthAnchor).isActive = true
        stackView.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true

        bottomSeparatorView.topAnchor.constraint(equalTo: stackView.bottomAnchor, constant: 4).isActive = true
        bottomSeparatorView.widthAnchor.constraint(equalTo: widthAnchor).isActive = true
        bottomSeparatorView.heightAnchor.constraint(equalToConstant: 0.5).isActive = true


    }



    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

}


回答4:

let collection :UICollectionView = {
   let layout = UICollectionViewFlowLayout()
    let collection = UICollectionView(frame: CGRect(x: 0, y: 0, width: 0, height: 0), collectionViewLayout: layout)
    layout.scrollDirection = .horizontal
    collection.translatesAutoresizingMaskIntoConstraints = false
    collection.backgroundColor = .clear
    return collection
}()


回答5:

override func awakeFromNib() {
    super.awakeFromNib()
    let overlayView = UIView()
    overlayView.backgroundColor = UIColor.red
    overlayView.frame = CGRect(x: 10, y: (350/2) - 50, width: 100, height: 100)
    self.addSubview(overlayView)
}