Reworking a Past Project
On the first day, I decided to start on the collection view that will be the products navigator/manual. I will use xib to design the cells I will use in my project. I also keep my project organized using better constants.
What I’m doing differently, day 1:
- Using Xib files for cells.
- Using MVC for project structure.
- The above also helps keeps constants much safer and organized.

Cells
Each cell and it’s product name and image.

class ProductCell: UICollectionViewCell {
@IBOutlet weak var stackView: UIStackView!
@IBOutlet weak var image: UIImageView!
@IBOutlet weak var label: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
//MARK:Set Stackview Height&Width
self.addConstraint(NSLayoutConstraint(
item: self.stackView!,
attribute: NSLayoutConstraint.Attribute.width,
relatedBy: NSLayoutConstraint.Relation.equal,
toItem: nil,
attribute: NSLayoutConstraint.Attribute.notAnAttribute,
multiplier: 1, constant: K.ObjectSizes.ProductsPage.CollectionCell.cellWidth))
self.addConstraint(NSLayoutConstraint(
item: self.stackView!,
attribute: NSLayoutConstraint.Attribute.height,
relatedBy: NSLayoutConstraint.Relation.equal,
toItem: nil,
attribute: NSLayoutConstraint.Attribute.notAnAttribute,
multiplier: 1, constant: K.ObjectSizes.ProductsPage.CollectionCell.cellHeight))
}
}
Collection
The collection will have 2 cells per row, with a brand title at the top.
class ProductsViewController: UIViewController {
// MARK: BRAND LABEL
@IBOutlet weak var brandLabel: UILabel!
// MARK: COLLECTION VIEW
@IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
//Register nib
collectionView.register(UINib(nibName: K.CellNames.ProductCell.nibName, bundle: nil), forCellWithReuseIdentifier: K.CellNames.ProductCell.identifier)
}
}
extension ProductsViewController: UICollectionViewDataSource, UICollectionViewDelegate {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 29
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: K.CellNames.ProductCell.identifier, for: indexPath) as! ProductCell
cell.label.text = "Big Red Apple"
return cell
}
}
extension ProductsViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let cellWidth = K.ObjectSizes.ProductsPage.CollectionCell.cellWidth
let cellHeight = K.ObjectSizes.ProductsPage.CollectionCell.cellHeight
return CGSize(width: cellWidth, height: cellHeight)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return CGFloat(K.ObjectSizes.ProductsPage.StackView.minimumLineSpacing)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return CGFloat(K.ObjectSizes.ProductsPage.StackView.minimumInteritemSpacing)
}
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets.zero
}
}
Constants
For structure, I am keeping central information such as identifiers, keys, paths, and values in a struct.
struct K {
struct CellNames {
struct ProductCell {
static let nibName = "ProductCell"
static let identifier = "ReusableProductCell"
}
}
struct ObjectSizes {
struct ProductsPage {
struct StackView {
//MARK: Adjustable
//Update this when change stackView H/W.
static let stackWidth = 414.0
static let stackHeight = 702.5
static let cellSpacing = 3.0
static let cellsPerRow = 2.0
//MARK: Set values
static let minimumInteritemSpacing = 1.0
static let minimumLineSpacing = 3.0
}
struct CollectionCell {
// Scaling cell sizing
// Denominator: cells per row
static let cellWidth = CGFloat(
-K.ObjectSizes.ProductsPage.StackView.cellSpacing
+
(K.ObjectSizes.ProductsPage.StackView.stackWidth
/
K.ObjectSizes.ProductsPage.StackView.cellsPerRow)
)
static let cellHeight =
CGFloat(
-K.ObjectSizes.ProductsPage.StackView.minimumLineSpacing
+
K.ObjectSizes.ProductsPage.StackView.stackHeight/3
// Div(3) Assuming 2 cells per row.
)
}
}
}
}
In the sub struct ObjectSizes, I decided to keep object sizes and sizing logic in Constants. The reason is because I was struggling to display proportional cells in my collection view. So, I made cell size a constant and applied them both to the cell itself and the collection view layout sizeforitemat. There must be a better method to this which I will find later.