Related
enter image description hereI make the word game, I have a word, this word needs to be divided into characters and each character should be added to a separate cell and there would be a space between the words, while using a custom class for the label. To do this, I use collection viewcells, I could not add a character to each cell, I was only able to transfer a whole word to each cell. Please help solve this problem.
P.S I added screenshots as it should be and as it isenter image description here
My code
ViewController.swift
import UIKit
class ViewController: UIViewController {
let cellID = "Cell"
let word = "Hello My People"
var index = 0
var targets = [TargetView]()
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 12
layout.minimumInteritemSpacing = 3
let collectionView1 = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView1.backgroundColor = .red
collectionView1.translatesAutoresizingMaskIntoConstraints = false
return collectionView1
}()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .brown
view.addSubview(collectionView)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(CharCell.self, forCellWithReuseIdentifier: cellID)
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16).isActive = true
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16).isActive = true
collectionView.topAnchor.constraint(equalTo: view.topAnchor, constant: 400).isActive = true
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -70).isActive = true
//var anagram1 = word.count
}
}
extension ViewController: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//
// var anagram1 = word
// //var leg = anagram1.count
////
//// //targets = []
// for (index,letter) in anagram1.enumerated() {
// let target = TargetView(letter: letter, sideLength: 15)
// if letter != " " {
// // let target = TargetView(letter: letter, sideLength: 15)
//// target.center = CGPoint(x: xOffset + CGFloat(index) /* * 20 */ * (15 + tileMargin) - view.frame.minX, y: UIScreen.main.bounds.size.height - 100) //100 //UIScreen.main.bounds.size.height - CGFloat(index) * 50
////
//// view.addSubview(target)
////
// //targets.append(target)
// //stackView.addArrangedSubview(target)
// targets.append(target)
// return 15
// }
// }
if index < word.count {
return word.count
} else {
return 0
}
//return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellID, for: indexPath) as! CharCell
for (index,letter) in word.enumerated() {
let target = TargetView(letter: letter, sideLength: 15)
if letter != " " {
// let target = TargetView(letter: letter, sideLength: 15)
targets.append(target)
cell.label.text = String(letter)
}
}
cell.label.text = word
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 30, height: 30)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 15, left: 0, bottom: 0, right: 0)
}
}
CharCell.swift
import UIKit
class CharCell: UICollectionViewCell {
var label1 = [TargetView]()
lazy var label: UILabel = {
let label = UILabel()
label.backgroundColor = .cyan
label.textAlignment = .left
label.font = .boldSystemFont(ofSize: 10)
label.text = "_"//String(letter).uppercased()
label.textColor = .black
label.numberOfLines = 3
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupCell()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupCell() {
backgroundColor = .white
label.frame = CGRect(x: 0, y: 1, width: frame.width , height: frame.height )
self.addSubview(label)
}
}
TargetView.swift
import UIKit
class TargetView: UILabel {
var letter: Character!
var isMatch = false
init(letter: Character, sideLength: CGFloat) {
self.letter = letter
//let image = UIImage(named: "slot")
//super.init(image: image)
//let scale = CGRect(x: 0, y: 0, width: (image?.size.width)! * scale, height: (image?.size.height)! * scale)
super.init(frame: CGRect(x: 0, y: 0, width: 15, height: 30))
self.backgroundColor = .red
self.textAlignment = .center
self.font = .boldSystemFont(ofSize: 60.0 / 3)
self.text = "_"//String(letter).uppercased()
self.textColor = .white
self.lineBreakMode = .byWordWrapping
self.adjustsFontSizeToFitWidth = true
self.translatesAutoresizingMaskIntoConstraints = false
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
The problem is you’re setting cell.label.text to word in every cell. Just split the phrase into components and add them to an array. In my example, I simplified it.
You'll likely need to adapt it to your app, but here's a quick implementation just to get you going.
import UIKit
class ViewController: UIViewController {
let cellID = "Cell"
let word = "Hello My People"
var arr = [String]()
lazy var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.minimumLineSpacing = 12
layout.minimumInteritemSpacing = 3
let collectionView1 = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView1.backgroundColor = .gray
collectionView1.translatesAutoresizingMaskIntoConstraints = false
return collectionView1
}()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
view.backgroundColor = .brown
view.addSubview(collectionView)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: cellID)
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: 16).isActive = true
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -16).isActive = true
collectionView.topAnchor.constraint(equalTo: view.topAnchor, constant: 400).isActive = true
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -70).isActive = true
for char in word {
arr.append(String(char))
}
}
}
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return arr.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellID, for: indexPath)
cell.backgroundColor = .red
let lbl = UILabel()
lbl.translatesAutoresizingMaskIntoConstraints = false
let cellText = arr[indexPath.item]
lbl.text = cellText
if cellText == " " {
cell.backgroundColor = .clear
}
cell.addSubview(lbl)
lbl.centerXAnchor.constraint(equalTo: cell.centerXAnchor).isActive = true
lbl.centerYAnchor.constraint(equalTo: cell.centerYAnchor).isActive = true
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 35, height: 35)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 15, left: 0, bottom: 0, right: 0)
}
}
Result:
I'm trying add a bottom border to a textfield inside a UICollectionViewCell, I registered the cell inside a view controller where my collection view is. But to set the size of the bottom border I need to the it own size, and I don't know how to do it inside the collection view cell, so Im trying to pass It to the view controller where It Is registered, but no success yet.
*Obs: I cut out some parts of the code because is not relevant.
UICollectionViewCell
class NameStepCell: UICollectionViewCell {
let safeAreaHolder: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
let title: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.font = UIFont.boldSystemFont(ofSize: 40)
label.text = "What is\nyour\nname?"
return label
}()
let txtFieldStack: UIStackView = {
let stack = UIStackView()
stack.translatesAutoresizingMaskIntoConstraints = false
stack.alignment = .center
stack.axis = .horizontal
stack.distribution = .fillEqually
stack.spacing = 20
return stack
}()
let nameField: UITextField = {
let txtFld = UITextField()
txtFld.keyboardType = UIKeyboardType.default
txtFld.textContentType = UITextContentType.name
txtFld.autocapitalizationType = UITextAutocapitalizationType.words
txtFld.autocorrectionType = .no
txtFld.textColor = UIColor.black
return txtFld
}()
let lastNameField: UITextField = {
let txtFld = UITextField()
txtFld.keyboardType = UIKeyboardType.default
txtFld.textContentType = UITextContentType.familyName
txtFld.autocapitalizationType = UITextAutocapitalizationType.words
txtFld.autocorrectionType = .no
txtFld.textColor = UIColor.black
return txtFld
}()
override init(frame: CGRect) {
super.init(frame: frame)
configuringView()
configuringTitle()
configuringTxtField()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func configuringView(){
addSubview(safeAreaHolder)
safeAreaHolder.topAnchor.constraint(equalTo: topAnchor).isActive = true
safeAreaHolder.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16).isActive = true
safeAreaHolder.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
safeAreaHolder.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16).isActive = true
}
func configuringTitle(){
safeAreaHolder.addSubview(title)
title.topAnchor.constraint(equalTo: safeAreaHolder.topAnchor, constant: 50).isActive = true
title.trailingAnchor.constraint(equalTo: safeAreaHolder.trailingAnchor).isActive = true
title.leadingAnchor.constraint(equalTo: safeAreaHolder.leadingAnchor).isActive = true
}
func configuringTxtField(){
safeAreaHolder.addSubview(txtFieldStack)
txtFieldStack.topAnchor.constraint(equalTo: title.bottomAnchor, constant: 50).isActive = true
txtFieldStack.trailingAnchor.constraint(equalTo: safeAreaHolder.trailingAnchor).isActive = true
txtFieldStack.leadingAnchor.constraint(equalTo: safeAreaHolder.leadingAnchor).isActive = true
txtFieldStack.addArrangedSubview(nameField)
txtFieldStack.addArrangedSubview(lastNameField)
nameField.heightAnchor.constraint(equalToConstant: 45).isActive = true
lastNameField.heightAnchor.constraint(equalToConstant: 45).isActive = true
}
}
UIViewController
class SignupViewController: UIViewController, UICollectionViewDelegateFlowLayout, UICollectionViewDelegate, UICollectionViewDataSource{
let stepsCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.backgroundColor = .white
collectionView.contentInsetAdjustmentBehavior = UIScrollView.ContentInsetAdjustmentBehavior.never
collectionView.isPagingEnabled = true
collectionView.showsHorizontalScrollIndicator = false
collectionView.isScrollEnabled = false
return collectionView
}()
override func viewDidLoad() {
super.viewDidLoad()
stepsCollectionView.dataSource = self
stepsCollectionView.delegate = self
stepsCollectionView.register(NameStepCell.self, forCellWithReuseIdentifier: "nameStepId")
stepsCollectionView.register(GenderStepCell.self, forCellWithReuseIdentifier: "genderStepId")
stepsCollectionView.register(BirthdayStepCell.self, forCellWithReuseIdentifier: "birthdayStepId")
stepsCollectionView.register(EmailStepCell.self, forCellWithReuseIdentifier: "emailStepId")
stepsCollectionView.register(PasswordStepCell.self, forCellWithReuseIdentifier: "passwordStepId")
view.backgroundColor = .white
configuringBottomButton()
configuringStepCollectionView()
}
override func viewDidAppear(_ animated: Bool) {
}
Here is where I try to get the nameFied to add the border
override func viewDidLayoutSubviews() {
NameStepCell().self.nameField.addBottomBorder()
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 1 {
let genderCell = collectionView.dequeueReusableCell(withReuseIdentifier: "genderStepId", for: indexPath)
return genderCell
}else if indexPath.item == 2{
let birthdayCell = collectionView.dequeueReusableCell(withReuseIdentifier: "birthdayStepId", for: indexPath)
return birthdayCell
}else if indexPath.item == 3{
let emailCell = collectionView.dequeueReusableCell(withReuseIdentifier: "emailStepId", for: indexPath)
return emailCell
}else if indexPath.item == 4{
let passwordCell = collectionView.dequeueReusableCell(withReuseIdentifier: "passwordStepId", for: indexPath)
return passwordCell
}
let nameCell = collectionView.dequeueReusableCell(withReuseIdentifier: "nameStepId", for: indexPath)
return nameCell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: stepsCollectionView.frame.size.width, height: stepsCollectionView.frame.size.height)
}
}
Extension to textfield to add the bottom border
extension UITextField {
func addBottomBorder() {
let border = CALayer()
border.frame = CGRect(x: 0, y: 32, width: self.frame.size.width, height: 1)
border.cornerRadius = 2
border.masksToBounds = true
border.backgroundColor = UIColor.init(red: 112/255, green: 112/255, blue: 112/255, alpha: 1).cgColor
self.layer.masksToBounds = true
self.layer.addSublayer(border)
}
}
Instead of calling addBottomBar() inside viewDidLayoutSubviews, you can try something like this.
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
if indexPath.item == 1 {
let genderCell = collectionView.dequeueReusableCell(withReuseIdentifier: "genderStepId", for: indexPath)
return genderCell
}else if indexPath.item == 2{
let birthdayCell = collectionView.dequeueReusableCell(withReuseIdentifier: "birthdayStepId", for: indexPath)
return birthdayCell
}else if indexPath.item == 3{
let emailCell = collectionView.dequeueReusableCell(withReuseIdentifier: "emailStepId", for: indexPath)
return emailCell
}else if indexPath.item == 4{
let passwordCell = collectionView.dequeueReusableCell(withReuseIdentifier: "passwordStepId", for: indexPath)
return passwordCell
}
// Dequeue your NameStepCell from collection view
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "nameStepId", for: indexPath)
if let nameCell = cell as? NameStepCell {
// Add bottom border to it right here and return it
nameCell.nameField.addBottomBorder()
return nameCell
}
return cell
}
Edit:
Now you don't need to change anything in your SignUpViewController. Please replace your NameStepCell class with the below code.
class NameStepCell: UICollectionViewCell {
var safeAreaHolder: UIView!
var title: UILabel!
var txtFieldStack: UIStackView!
var nameField: UITextField!
var lastNameField: UITextField!
override init(frame: CGRect) {
super.init(frame: frame)
configuringView()
configuringTitle()
configuringTxtField()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
private extension NameStepCell {
func configuringView(){
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
self.safeAreaHolder = view
addSubview(safeAreaHolder)
safeAreaHolder.topAnchor.constraint(equalTo: topAnchor).isActive = true
safeAreaHolder.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -16).isActive = true
safeAreaHolder.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
safeAreaHolder.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 16).isActive = true
self.safeAreaHolder.layoutIfNeeded()
}
func configuringTitle(){
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.font = UIFont.boldSystemFont(ofSize: 40)
label.text = "What is\nyour\nname?"
self.title = label
safeAreaHolder.addSubview(title)
title.topAnchor.constraint(equalTo: safeAreaHolder.topAnchor, constant: 50).isActive = true
title.trailingAnchor.constraint(equalTo: safeAreaHolder.trailingAnchor).isActive = true
title.leadingAnchor.constraint(equalTo: safeAreaHolder.leadingAnchor).isActive = true
self.title.layoutIfNeeded()
}
func configuringTxtField(){
let stack = UIStackView()
stack.backgroundColor = .lightGray
stack.translatesAutoresizingMaskIntoConstraints = false
stack.alignment = .center
stack.axis = .horizontal
stack.distribution = .fillEqually
stack.spacing = 20
self.txtFieldStack = stack
safeAreaHolder.addSubview(txtFieldStack)
txtFieldStack.topAnchor.constraint(equalTo: title.bottomAnchor, constant: 50).isActive = true
txtFieldStack.trailingAnchor.constraint(equalTo: safeAreaHolder.trailingAnchor).isActive = true
txtFieldStack.leadingAnchor.constraint(equalTo: safeAreaHolder.leadingAnchor).isActive = true
self.txtFieldStack.layoutIfNeeded()
self.nameField = getTextField(.name)
self.lastNameField = getTextField(.familyName)
txtFieldStack.addArrangedSubview(nameField)
txtFieldStack.addArrangedSubview(lastNameField)
nameField.heightAnchor.constraint(equalToConstant: 45).isActive = true
lastNameField.heightAnchor.constraint(equalToConstant: 45).isActive = true
// After adding constraints, you should call 'layoutIfNeeded()' which recomputes the size and position based on the constraints you've set
self.nameField.layoutIfNeeded()
self.lastNameField.layoutIfNeeded()
self.nameField.addBottomBorder()
self.lastNameField.addBottomBorder()
}
func getTextField(_ textContentType: UITextContentType) -> UITextField {
let textField = UITextField()
textField.keyboardType = .default
textField.textContentType = textContentType
textField.autocapitalizationType = .words
textField.autocorrectionType = .no
textField.textColor = .black
textField.placeholder = textContentType.rawValue // P.S. Remove placeholder if you don't need.
return textField
}
}
I am trying to laod an array of images to a collectionview that is within a UIViewController. The UIImageView within my custom UICollectionViewCell is not extending to the bounds of the cell and I do not understand why. Below is my code.
ViewController:
var dragCollectionView: UICollectionView!
var dragCollectionViewWidth: CGFloat!
let borderInset: CGFloat = 3
var interCellSpacing: CGFloat = 3
var spacingBetweenRows: CGFloat = 3
let container1: UIView = {
let v = UIView()
v.backgroundColor = UIColor.yellow
return v
}()
override func viewDidLoad() {
super.viewDidLoad()
margins = view.layoutMarginsGuide
view.backgroundColor = UIColor.white
view.addSubview(container1)
container1.translatesAutoresizingMaskIntoConstraints = false
container1.heightAnchor.constraint(equalTo: margins.heightAnchor, multiplier: 0.5).isActive = true
container1.leadingAnchor.constraint(equalTo: margins.leadingAnchor).isActive = true
container1.trailingAnchor.constraint(equalTo: margins.trailingAnchor).isActive = true
container1.topAnchor.constraint(equalTo: margins.topAnchor).isActive = true
setUpCollectionViewForPuzzlePieces()
}
override func viewDidLayoutSubviews() {
print("")
print("viewDidLayoutSubviews ...")
dragCollectionViewWidth = dragCollectionView.frame.width
dragCollectionView.translatesAutoresizingMaskIntoConstraints = false
dragCollectionView.topAnchor.constraint(equalTo: container1.topAnchor).isActive = true
dragCollectionView.bottomAnchor.constraint(equalTo: container1.bottomAnchor).isActive = true
dragCollectionView.leftAnchor.constraint(equalTo: container1.leftAnchor).isActive = true
dragCollectionView.rightAnchor.constraint(equalTo: container1.rightAnchor).isActive = true
setupLayoutDragCollectionView()
}
private func setUpCollectionViewForPuzzlePieces(){
let frame = CGRect.init(x: 0, y: 0, width: 100, height: 100)
layout = UICollectionViewFlowLayout.init()
dragCollectionView = UICollectionView.init(frame: frame, collectionViewLayout: layout)
dragCollectionView.backgroundColor = UIColor.gray
dragCollectionView.delegate = self
dragCollectionView.dataSource = self
container1.addSubview(dragCollectionView)
dragCollectionView.translatesAutoresizingMaskIntoConstraints = false
dragCollectionView.topAnchor.constraint(equalTo: container1.topAnchor).isActive = true
dragCollectionView.bottomAnchor.constraint(equalTo: container1.bottomAnchor).isActive = true
dragCollectionView.leftAnchor.constraint(equalTo: container1.leftAnchor).isActive = true
dragCollectionView.rightAnchor.constraint(equalTo: container1.rightAnchor).isActive = true
// Register UICollectionViewCell
dragCollectionView.register(GirdyPickCollectionCell.self, forCellWithReuseIdentifier: cellId)
}
private func setupLayoutDragCollectionView(){
layout.minimumInteritemSpacing = interCellSpacing
layout.minimumLineSpacing = spacingBetweenRows
layout.sectionInset = UIEdgeInsets.init(top: borderInset, left: borderInset, bottom: borderInset, right: borderInset)
guard
let collectionViewWidth = dragCollectionViewWidth,
let numRows = numberOfGridColumns else{return}
print("numRows: \(numRows)")
let cellWidth = getCellWidth(numRows: numRows, collectionViewWidth: collectionViewWidth, interCellSpace: interCellSpacing, borderInset: borderInset)
layout.estimatedItemSize = CGSize.init(width: cellWidth, height: cellWidth)
print("margins.layoutFrame.width: \(margins.layoutFrame.width)")
print("collectionViewWidth: \(collectionViewWidth)")
print("cellWidth: \(cellWidth)")
print("")
}
private func getCellWidth(numRows: CGFloat, collectionViewWidth: CGFloat, interCellSpace: CGFloat, borderInset: CGFloat) -> CGFloat{
let numSpacing = numRows - 1
let cellWidth = (collectionViewWidth - interCellSpace * numSpacing - borderInset * 2) / numRows
return cellWidth
}
extension StartGameViewController: UICollectionViewDataSource{
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
guard let data = puzzlePieces else {return 0}
return data.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = dragCollectionView.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath) as! GirdyPickCollectionCell
guard let data = puzzlePieces else {return cell}
cell.imageView.image = data[indexPath.row].image
return cell
}
}
My custom UICollectionViewCell:
class GirdyPickCollectionCell: UICollectionViewCell {
var image: UIImage?
var imageView: UIImageView = {
let imgView = UIImageView()
return imgView
}()
override init(frame: CGRect) {
super.init(frame: frame)
self.addSubview(imageView)
self.backgroundColor = UIColor.red.withAlphaComponent(0.3)
setUpLayout()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setUpLayout(){
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
imageView.widthAnchor.constraint(equalToConstant: frame.width).isActive = true
imageView.heightAnchor.constraint(equalToConstant: frame.height).isActive = true
}
}
CONSOLE:
viewDidLayoutSubviews ...
numRows: 5.0
margins.layoutFrame.width: 343.0
collectionViewWidth: 100.0
cellWidth: 16.4
viewDidLayoutSubviews ...
numRows: 5.0
margins.layoutFrame.width: 343.0
collectionViewWidth: 343.0
cellWidth: 65.0
What I am currently getting:
Implement UICollectionViewDelegateFlowLayout in your view controller and provide the size in collectionView:layout:sizeForItemAtIndexPath:
func collectionView(_ collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAt indexPath: IndexPath) -> CGSize {
let kWhateverHeightYouWant = 100
return CGSize(width: collectionView.bounds.size.width, height: CGFloat(kWhateverHeightYouWant))
}
You can add constraints to Left (or leading), Top, Right (or trailing) and bottom of the imageView.
This will also help you to set padding between the frames if required.
Use this code:
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.rightAnchor.constraint(equalTo: self.rightAnchor).isActive = true
imageView.leftAnchor.constraint(equalTo: self.leftAnchor).isActive = true
imageView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
imageView.bottomAnchor.constraint(equalTo: self.bottomAnchor).isActive = true
I think you should set all edges constraints instead of giving width and height,
Try to add constraints like this
private func setUpLayout(){
imageView.translatesAutoresizingMaskIntoConstraints = false
imageView.topAnchor.constraint(equalTo: self.topAnchor).isActive = true
imageView.leftAnchor.constraint(equalTo: leftAnchor).isActive = true
imageView.rightAnchor.constraint(equalTo: rightAnchor).isActive = true
imageView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
}
I'm trying to create an UICollectionView which can scroll horizontally and vertically.
Here are my codes:
Here is the Model:
import UIKit
class AppCategory: NSObject {
var name: String?
var apps: [App]?
static func sampleAppCategories() -> [AppCategory] {
// Chapter 1
let chapter1 = AppCategory()
chapter1.name = NSLocalizedString("CHAPTER 1: ", comment: "1") + NSLocalizedString("19 Sections", comment: "title")
var apps1 = [App]()
let chapter1App = App()
chapter1App.imageName = "IMG_2487"
let chapter11App = App()
chapter11App.imageName = "IMG_2502"
let chapter12App = App()
chapter12App.imageName = "IMG_2507"
apps1.append(chapter1App)
apps1.append(chapter11App)
apps1.append(chapter12App)
chapter1.apps = apps1
// Chapter 2
let chapter2 = AppCategory()
chapter2.name = NSLocalizedString("CHAPTER 2: ", comment: "2") + NSLocalizedString("19 Sections", comment: "title")
var apps2 = [App]()
let chapter2App = App()
chapter2App.imageName = "IMG_2508"
apps2.append(chapter2App)
chapter2.apps = apps2
// Chapter 3
let chapter3 = AppCategory()
chapter3.name = NSLocalizedString("CHAPTER 3: ", comment: "title") + NSLocalizedString("19 Sections", comment: "title")
var apps3 = [App]()
let chapter3App = App()
chapter3App.imageName = "IMG_2510"
apps3.append(chapter3App)
chapter3.apps = apps3
// Chapter 4
let chapter4 = AppCategory()
chapter4.name = NSLocalizedString("CHAPTER 4: ", comment: "title") + NSLocalizedString("19 Sections", comment: "title")
var apps4 = [App]()
let chapter4App = App()
chapter4App.imageName = "IMG_2511"
apps4.append(chapter4App)
chapter4.apps = apps4
return [chapter1, chapter2, chapter3, chapter4]
}
}
class App: NSObject {
var imageName: String?
}
Here is the FeatureViewController:
import UIKit
class FeaturedViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var appCategories: [AppCategory]?
let verticalCellId = "verticalCellId"
let horizontalCellId = "horizontalCellId"
override func viewDidLoad() {
super.viewDidLoad()
collectionView?.backgroundColor = .white
appCategories = AppCategory.sampleAppCategories()
navigationItem.title = NSLocalizedString("Original", comment: "Original")
navigationController?.navigationBar.prefersLargeTitles = true
collectionView?.register(FeaturedVerticalCell.self, forCellWithReuseIdentifier: verticalCellId)
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if let count = appCategories?.count {
return count
}
return 0
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: verticalCellId, for: indexPath) as! FeaturedVerticalCell
cell.appCategory = appCategories?[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
switch UIDevice.current.userInterfaceIdiom {
case .phone:
collectionView.reloadData()
return CGSize(width:view.frame.width, height: view.frame.width / 5 * 4 )
case .pad:
let padding: CGFloat = 50
let collectionViewSize = collectionView.frame.size.width - padding
collectionView.reloadData()
return CGSize(width: collectionViewSize / 5 * 4, height: collectionViewSize / 5 * 3 )
case .tv:
break
case .carPlay:
break
case .unspecified:
break
}
return CGSize(width: 0, height: 0)
}
}
Here is the FeaturedVerticalCell:
import UIKit
struct Titles {
var title: String?
var images:[String]
}
class FeaturedVerticalCell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
let horizontalCellId = "horizontalCellId"
var appCategory: AppCategory? {
didSet {
if let name = appCategory?.name {
titleLabel.text = name
}
}
}
let horizontalCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.backgroundColor = UIColor.clear
collectionView.translatesAutoresizingMaskIntoConstraints = false
return collectionView
}()
let titleLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
if UIDevice.current.userInterfaceIdiom == .phone {
label.font = UIFont.systemFont(ofSize: 14.0, weight: UIFont.Weight.medium)
} else {
label.font = UIFont.systemFont(ofSize: 20.0, weight: UIFont.Weight.medium)
}
label.textAlignment = .left
label.textColor = UIColor.darkGray
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
horizontalCollectionView.dataSource = self
horizontalCollectionView.delegate = self
horizontalCollectionView.register(HorizontalCollectionViewCell.self, forCellWithReuseIdentifier: horizontalCellId)
addSubview(horizontalCollectionView)
horizontalCollectionView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 24).isActive = true
horizontalCollectionView.topAnchor.constraint(equalTo: self.topAnchor, constant: 36).isActive = true
horizontalCollectionView.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -24).isActive = true
horizontalCollectionView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 8).isActive = true
addSubview(titleLabel)
titleLabel.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 24).isActive = true
titleLabel.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -24).isActive = true
titleLabel.bottomAnchor.constraint(equalTo: horizontalCollectionView.topAnchor, constant: 0).isActive = true
titleLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 24).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if let count = appCategory?.apps?.count {
return count
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: horizontalCellId, for: indexPath) as! HorizontalCollectionViewCell
cell.app = appCategory?.apps?[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: frame.height * 4 / 5, height: frame.height * 4 / 5)
}
}
class HorizontalCollectionViewCell: UICollectionViewCell {
var app: App? {
didSet {
if let imageName = app?.imageName {
photoImageView.image = UIImage(named: imageName)
}
}
}
let photoImageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
iv.layer.cornerRadius = 10
iv.image = #imageLiteral(resourceName: "IMG_2545")
iv.layer.masksToBounds = true
iv.translatesAutoresizingMaskIntoConstraints = false
return iv
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(photoImageView)
photoImageView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 0).isActive = true
photoImageView.rightAnchor.constraint(equalTo: self.rightAnchor, constant: 0).isActive = true
photoImageView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
photoImageView.topAnchor.constraint(equalTo: self.topAnchor, constant: 0).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
But now I got a problem: the rows in horizontal sections will change somehow when I scroll vertically. Any way to get it back to work normally?
Don't know what's wrong there on earth, but finally I got it work. Here you go:
import UIKit
class FeaturedViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout, UISearchResultsUpdating {
func updateSearchResults(for searchController: UISearchController) {
print("SeachController tapped.")
}
let firstCellId = "cellfirstCellIdId"
var appCategories: [AppCategory]?
override func viewDidLoad() {
super.viewDidLoad()
appCategories = AppCategory.sampleAppCategories()
collectionView?.backgroundColor = UIColor.clear
collectionView?.register(CategoryCell.self, forCellWithReuseIdentifier: firstCellId)
navigationItem.title = NSLocalizedString("Original", comment: "Original")
navigationController?.navigationBar.prefersLargeTitles = true
let searchController = UISearchController(searchResultsController: nil)
searchController.searchResultsUpdater = self
searchController.dimsBackgroundDuringPresentation = false
navigationItem.hidesSearchBarWhenScrolling = true
self.navigationItem.searchController = searchController
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: firstCellId, for: indexPath) as! CategoryCell
cell.appCategory = appCategories?[indexPath.item]
return cell
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if let count = appCategories?.count {
return count
}
return 0
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: 300)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
}
Here is the cell:
import UIKit
class CategoryCell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
var appCategory: AppCategory? {
didSet {
if let name = appCategory?.name {
firstChapterLabel.text = name
}
}
}
let secondCellId = "secondCellId"
let appsCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.backgroundColor = UIColor.clear
collectionView.translatesAutoresizingMaskIntoConstraints = false
return collectionView
}()
let firstChapterLabel: UILabel = {
let label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
if UIDevice.current.userInterfaceIdiom == .phone {
label.font = UIFont.systemFont(ofSize: 14.0, weight: UIFont.Weight.medium)
} else {
label.font = UIFont.systemFont(ofSize: 20.0, weight: UIFont.Weight.medium)
}
label.textAlignment = .left
label.textColor = UIColor.darkGray
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(appsCollectionView)
appsCollectionView.dataSource = self
appsCollectionView.delegate = self
appsCollectionView.register(AppCell.self, forCellWithReuseIdentifier: secondCellId)
appsCollectionView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 16).isActive = true
appsCollectionView.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -16).isActive = true
appsCollectionView.topAnchor.constraint(equalTo: self.topAnchor, constant: 50).isActive = true
appsCollectionView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: 0).isActive = true
addSubview(firstChapterLabel)
firstChapterLabel.leftAnchor.constraint(equalTo: appsCollectionView.leftAnchor, constant: 16).isActive = true
firstChapterLabel.rightAnchor.constraint(equalTo: appsCollectionView.rightAnchor, constant: -16).isActive = true
firstChapterLabel.topAnchor.constraint(equalTo: self.topAnchor, constant: 24).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
if let count = appCategory?.apps?.count {
return count
}
return 0
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: secondCellId, for: indexPath) as! AppCell
cell.app = appCategory?.apps?[indexPath.item]
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: frame.height, height: frame.height)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 0
}
}
class AppCell: UICollectionViewCell {
var app: App? {
didSet {
if let imageName = app?.imageName {
photoImageView.image = UIImage(named: imageName)
}
}
}
let photoImageView: UIImageView = {
let iv = UIImageView()
iv.contentMode = .scaleAspectFill
iv.clipsToBounds = true
iv.layer.cornerRadius = 9
iv.layer.masksToBounds = true
iv.translatesAutoresizingMaskIntoConstraints = false
return iv
}()
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(photoImageView)
photoImageView.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 16).isActive = true
photoImageView.rightAnchor.constraint(equalTo: self.rightAnchor, constant: -16).isActive = true
photoImageView.bottomAnchor.constraint(equalTo: self.bottomAnchor, constant: -36).isActive = true
photoImageView.topAnchor.constraint(equalTo: self.topAnchor, constant: 36).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
And the model stays as it was described in the question.
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.main.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.register(MyCollectionViewCell.self, forCellWithReuseIdentifier: cellReuseIdentifier)
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "collectionCell")
collectionView.delegate = self
collectionView.dataSource = self
collectionView.backgroundColor = UIColor.cyan
self.view.addSubview(collectionView)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int
{
return self.items.count
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellReuseIdentifier, for: indexPath) as! MyCollectionViewCell
cell.backgroundColor = UIColor.green
return cell
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize
{
let width = (screenSize.width-leftAndRightPaddings)/numberOfItemsPerRow
return CGSize(width: width, height: width)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt 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).
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")
}
}
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.
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")
}
}
Response of Bob Lee updated to Swift 5.1
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.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, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionview.dequeueReusableCell(withReuseIdentifier: cellId, for: indexPath as 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 = NSLayoutConstraint.Axis.horizontal
sv.alignment = UIStackView.Alignment.center
sv.distribution = UIStackView.Distribution.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")
}
}
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
}()