Make collection view height dynamic depending on content - ios

I have a collection view that contains a cell with varying width (it has a label inside it):
public class TagView: UIView {
let textLabel: UILabel = {
let label = UILabel()
label.textColor = .black
label.textAlignment = .center
label.font = UIFont.systemFont(ofSize: 15)
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
setupView()
setupLabel()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func setupView() {
backgroundColor = #colorLiteral(red: 0.03529411765, green: 0.6862745098, blue: 0.003921568627, alpha: 1)
backgroundColor = backgroundColor
layer.cornerRadius = 3
layer.masksToBounds = true
}
private func setupLabel() {
addSubview(textLabel)
textLabel.fillToSuperview(constant: 3)
}
}
How do I make the collection view's height dynamic? The problem is that at init time I don't know what frame I should give to the collection view, so I just give zero:
let layout = UICollectionViewFlowLayout()
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
How do I make the collection view height dynamic?
I have also looked into the sizeForItem method:
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let view = TagView()
let data = tags[indexPath.row]
view.textLabel.text = data
view.layoutSubviews()
return view.frame.size
}
but I think this returns a size of zero width and heigth.

First here set an assumption height , but the width should be known
let collectionView = UICollectionView(frame:CGRect(x:0,y:20,width:self.view.frame.width,height:300), collectionViewLayout: layout)
Then in sizeForItemAt
let fixedWidth = (collectionView.frame.width - 40 ) / 5 // say here you need 5 items / row
let label = UILabel()
label.numberOfLines = 0
label.font = UIFont.systemFont(ofSize: 15)
let si = label.sizeThatFits(CGSize(width:fixedWidth, height: CGFloat.greatestFiniteMagnitude))
// si.height is the needed height with 6 padding from top and bottom according to your constant in tagView
return CGSize(width:fixedWidth + 6.0 ,height:si.height)
For a total height , create a function from above and call it with all your items then add the heights and set them to collectionView's height

Related

UIImageView view in UICollectionView cell is not resizing to cell width

I'm creating simple UICollectionView with 3 column per row cells.
My cell is simple - just UIImageView stretched to 4 sides:
class FollowerCell: UICollectionViewCell {
static let reuseID = "FollowerCell"
var avatarImageView:UIImageView!
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func configure() {
avatarImageView = UIImageView()
addSubview(avatarImageView)
contentView.layer.borderColor = UIColor.red.cgColor
contentView.layer.cornerRadius = 5
contentView.layer.borderWidth = 5
avatarImageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
avatarImageView.topAnchor.constraint(equalTo: contentView.topAnchor),
avatarImageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
avatarImageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
avatarImageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
])
avatarImageView.image = UIImage(named: "avatar-placeholder")
}
}
In ViewController I define width on cells by implementing UICollectionViewDelegateFlowLayout's method sizeForItemAt:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let width = self.view.bounds.width
let itemWidth = width / 3
return CGSize(width: itemWidth, height: itemWidth)
}
And i have strange result - my UIImageView size ignores cell size (which is red rectangle):
Github: https://github.com/afirthes/TryUIViewCollection
When I try to do the same in storyboard, it seems to work well:
What i'm missing when creating UICollectionView programmatically ?
Im following tutorial from 2021 where it works just fine, seems something was changed in XCode 11.
Main change
contentView.addSubview(avatarImageView)
Full class
import UIKit
class FollowerCell: UICollectionViewCell {
static let reuseID = "FollowerCell"
var avatarImageView:UIImageView!
override init(frame: CGRect) {
super.init(frame: frame)
configure()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
private func configure() {
avatarImageView = UIImageView()
contentView.addSubview(avatarImageView)
contentView.layer.borderColor = UIColor.red.cgColor
contentView.layer.cornerRadius = 5
contentView.layer.borderWidth = 5
avatarImageView.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
avatarImageView.topAnchor.constraint(equalTo: contentView.topAnchor),
avatarImageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
avatarImageView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
avatarImageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
])
avatarImageView.image = UIImage(named: "avatar-placeholder")
}
}

Calculating Size of Cell for CollectionView Mosaic Layout

I'm trying to make a mosaic collection view layout similar to Google's Keep app. I've subclassed UICollectionViewLayout similar to the many tutorials found online. In order to properly layout the collection view cells, the calling class must implement a delegate, HeightForCellAtIndexPath method to get the cell's height. In my case, I also get the cell's width to create 1, 2 or 3 column layouts.
In all of the tutorials, the height of the cell's content is known and does not need to be computed. In my case, the size of content is not known and needs to be computed. I've tried many different ways of calculating this but none work perfectly. My latest attempt entails creating a CardContent class and adding that to a cell's contentView in cellForItemAt and also instantiate a CardContent instance in HeightForCellAtIndexPath to calculate the size of the content that is passed to the layout class.
I'm sure there are many problems with my methodology, but from what I can gather, the issue appears to be with the multi-line labels not laid out correctly in HeightForCellAtIndexPath in that the labels are not wrapping to multi line and remain as a single line thus giving me an incorrect height of the contentView.
CardContentCell.swift
import UIKit
class CardContentCell: UICollectionViewCell {
var todoList: TodoList! {
didSet {
self.backgroundColor = UIColor(todoList.color)
}
}
override init(frame: CGRect) {
super.init(frame: frame)
self.layer.cornerRadius = 5.0
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
CardContent.swift
Edit: Added createLineItem method. See answer below.
class CardContent: UIStackView {
var todoList: TodoList!
var verticalItemSpacing: CGFloat = 10.0
var cellWidth: CGFloat!
init(todoList: TodoList, cellWidth: CGFloat = 0.0) {
self.todoList = todoList
self.cellWidth = cellWidth
super.init(frame: CGRect(x: 0, y: 0, width: cellWidth, height: 0))
self.axis = .vertical
self.alignment = .fill
self.distribution = .fill
self.contentMode = .scaleToFill
self.spacing = 10.0
layoutContent()
}
required init(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func createTitleLabel(title: String) -> UILabel {
let label = UILabel()
label.text = title
label.font = label.font.withSize(20.0)
label.numberOfLines = 2
label.lineBreakMode = .byTruncatingTail
label.translatesAutoresizingMaskIntoConstraints = false
return label
}
func createItemLabel(text: String) -> UILabel {
let label = UILabel()
label.text = text
label.font = label.font.withSize(17.0)
label.numberOfLines = 3
label.lineBreakMode = .byTruncatingTail
label.translatesAutoresizingMaskIntoConstraints = false
label.sizeToFit()
return label
}
func createLineItem(text: String) -> UIStackView {
let hstack = UIStackView()
hstack.axis = .horizontal
hstack.alignment = .fill
hstack.distribution = .fillProportionally
let imgView = createImgView(withFont: lineItemFont)
let textLabel = createItemLabel(text: text)
hstack.addArrangedSubview(imgView)
hstack.addArrangedSubview(textLabel)
return hstack
}
func layoutContent() {
self.addArrangedSubview(createTitleLabel(title: todoList.title))
for todo in todoList.todos.prefix(6) {
let lineItem = createLineItem(text: todo.text)
self.addArrangedSubview(lineItem)
}
}
}
MyCollectionView.swift
extension MyCollectionView: UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: cellID, for: indexPath) as! CardContentCell
cell.todoList = todoLists[indexPath.row]
let content = CardContent(todoList: cell.todoList)
cell.contentView.addSubview(content)
content.pinTopAndSides(to: cell.contentView) // See extension below
return cell
}
}
extension MyCollectionView: CardLayoutDelegate {
func collectionView(_ collectionView: UICollectionView, HeightForCellAtIndexPath indexPath: IndexPath, cellWidth: CGFloat) -> CGFloat {
let todoList = todoLists[indexPath.row]
let stackView = CardContent(todoList: todoList, cellWidth: cellWidth)
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.setNeedsLayout()
stackView.layoutIfNeeded()
let size = stackView.frame.size
return size.height
}
}
extension UIView {
func pinTopAndSides(to other: UIView) {
translatesAutoresizingMaskIntoConstraints = false
leadingAnchor.constraint(equalTo: other.leadingAnchor).isActive = true
trailingAnchor.constraint(equalTo: other.trailingAnchor).isActive = true
topAnchor.constraint(equalTo: other.topAnchor).isActive = true
}
}
The result is, if there are always 6 line items, then the computed height is always 230 (in a 2 column layout). In the screen shot below, the cell is colored while the rest of the content overflows.
Barring a better solution, the answer for me involved not using a nested horizontal UIStackview. That was fraught with unknowns and hard to diagnose auto layout issues. Instead, I used a UIView and added my own constraints.
Here's the method that creates said view. It's interesting that no one took a close enough look at my question that in my hurry to copy and past, I omitted this most crucial method in the original post. I will update the question with the original implementation of this method for reference.
func createLineItem(text: String) -> UIView {
let view = UIView()
let imgView = createImgView(withFont: lineItemFont)
imgView.translatesAutoresizingMaskIntoConstraints = false
let textLabel = createItemLabel(text: text)
textLabel.translatesAutoresizingMaskIntoConstraints = false
imgView.tintColor = self.textColor
view.addSubview(imgView)
view.addSubview(textLabel)
imgView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
imgView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
textLabel.leadingAnchor.constraint(equalTo: imgView.trailingAnchor, constant: 5.0).isActive = true
textLabel.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
textLabel.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
textLabel.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
return view
}
And,as for the HeightForCellAtIndexPath delegate function, setting the widthAnchor to the cell width provided the correct height of the cell:
func collectionView(_ collectionView: UICollectionView, HeightForCellAtIndexPath indexPath: IndexPath, cellWidth: CGFloat) -> CGFloat {
let stackView = CardContent(todoList: todoList)
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.widthAnchor.constraint(equalToConstant: cellWidth).isActive = true
stackView.setNeedsLayout()
stackView.layoutIfNeeded()
let size = stackView.frame.size
return size.height
}

UIScrollView not showing up in the view

I am implementing a UIScrollView in a CollectionViewCell. I have a custom view which the scroll view should display, hence I am performing the following program in the CollectionViewCell. I have created everything programmatically and below is my code :
struct ShotsCollections {
let title: String?
}
class ShotsMainView: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
containerScrollView.contentSize.width = frame.width * CGFloat(shotsData.count)
shotsData = [ShotsCollections.init(title: "squad"), ShotsCollections.init(title: "genral")]
var i = 0
for data in shotsData {
let customview = ShotsMediaView(frame: CGRect(x: containerScrollView.frame.width * CGFloat(i), y: 0, width: containerScrollView.frame.width, height: containerScrollView.frame.height))
containerScrollView.addSubview(customview)
i += 1
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
var shotsData = [ShotsCollections]()
var containerScrollView: UIScrollView = {
let instance = UIScrollView()
instance.isScrollEnabled = true
instance.bounces = true
instance.backgroundColor = blueColor
return instance
}()
private func setupViews() { //These are constraints by using TinyConstraints
addSubview(containerScrollView)
containerScrollView.topToSuperview()
containerScrollView.bottomToSuperview()
containerScrollView.rightToSuperview()
containerScrollView.leftToSuperview()
}
}
Now the issue is, while the scrollview is displayed, the content in it is not. I on printing the contentSize and frame of the scrollview, it displays 0. But if I check the Debug View Hierarchy, scrollview containes 2 views with specific frames.
I am not sure whats going wrongs. Any help is appreciated.
When you are adding customView in your containerScrollView, you are not setting up the constraints between customView and containerScrollView.
Add those constraints and you will be able to see your customViews given that your customView has some height. Also, when you add more view, you would need to remove the bottom constraint of the last added view and create a bottom constraint to the containerScrollView with the latest added view.
I created a sample app for your use case. I am pasting the code and the resultant screen shot below. Hope this is the functionality you are looking for. I suggest you paste this in a new project and tweak the code until you are satisfied. I have added comments to make it clear.
ViewController
import UIKit
class ViewController: UIViewController {
// Initialize dummy data array with numbers 0 to 9
var data: [Int] = Array(0..<10)
override func loadView() {
super.loadView()
// Add collection view programmatically
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.register(ShotsMainView.self, forCellWithReuseIdentifier: ShotsMainView.identifier)
self.view.addSubview(collectionView)
NSLayoutConstraint.activate([
self.view.topAnchor.constraint(equalTo: collectionView.topAnchor),
self.view.bottomAnchor.constraint(equalTo: collectionView.bottomAnchor),
self.view.leadingAnchor.constraint(equalTo: collectionView.leadingAnchor),
self.view.trailingAnchor.constraint(equalTo: collectionView.trailingAnchor),
])
collectionView.delegate = self
collectionView.dataSource = self
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.backgroundColor = UIColor.white
self.view.addSubview(collectionView)
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = UIColor.white
}
}
extension ViewController: UICollectionViewDelegate, UICollectionViewDataSource {
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: ShotsMainView.identifier, for: indexPath) as! ShotsMainView
return cell
}
}
extension ViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// The cell dimensions are set from here
return CGSize(width: collectionView.frame.size.width, height: 100.0)
}
}
ShotsMainView
This is the collection view cell
import UIKit
class ShotsMainView: UICollectionViewCell {
static var identifier = "Cell"
weak var textLabel: UILabel!
override init(frame: CGRect) {
// Initialize with zero frame
super.init(frame: frame)
// Add the scrollview and the corresponding constraints
let containerScrollView = UIScrollView(frame: .zero)
containerScrollView.isScrollEnabled = true
containerScrollView.bounces = true
containerScrollView.backgroundColor = UIColor.blue
containerScrollView.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(containerScrollView)
NSLayoutConstraint.activate([
self.topAnchor.constraint(equalTo: containerScrollView.topAnchor),
self.bottomAnchor.constraint(equalTo: containerScrollView.bottomAnchor),
self.leadingAnchor.constraint(equalTo: containerScrollView.leadingAnchor),
self.trailingAnchor.constraint(equalTo: containerScrollView.trailingAnchor)
])
// Add the stack view that will hold the individual items that
// in each row that need to be scrolled horrizontally
let stackView = UIStackView(frame: .zero)
stackView.distribution = .fill
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.axis = .horizontal
containerScrollView.addSubview(stackView)
stackView.backgroundColor = UIColor.magenta
NSLayoutConstraint.activate([
containerScrollView.leadingAnchor.constraint(equalTo: stackView.leadingAnchor),
containerScrollView.trailingAnchor.constraint(equalTo: stackView.trailingAnchor),
containerScrollView.topAnchor.constraint(equalTo: stackView.topAnchor),
containerScrollView.bottomAnchor.constraint(equalTo: stackView.bottomAnchor)
])
// Add individual items (Labels in this case).
for i in 0..<10 {
let label = UILabel(frame: .zero)
label.translatesAutoresizingMaskIntoConstraints = false
stackView.addArrangedSubview(label)
label.text = "\(i)"
label.font = UIFont(name: "System", size: 20.0)
label.textColor = UIColor.white
label.backgroundColor = UIColor.purple
label.layer.masksToBounds = false
label.layer.borderColor = UIColor.white.cgColor
label.layer.borderWidth = 1.0
label.textAlignment = .center
NSLayoutConstraint.activate([
label.heightAnchor.constraint(equalTo: self.heightAnchor, multiplier: 1.0, constant: 0.0),
label.widthAnchor.constraint(equalTo: self.widthAnchor, multiplier: 0.2, constant: 0.0)
])
}
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
Screenshot

How do I set up a label in my UICollectionView Cell?

I've been struggling with this for almost an entire day now and can't find a solution. I'm trying to create a UICollectionView within a view controller that has cells just with a single label in each of them. However, I can't seem to add the label as a subview to the cell no matter what I do. Here is the code I have in my main view controller:
var collectionView: UICollectionView!
func configureCollectionView()
{
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.itemSize = CGSize(width: 50, height: 20)
let y = interestsUnderline.frame.origin.y + 5
let width = interestsUnderline.frame.width
let frame = CGRect(x: 40, y: y, width: width, height: 30)
collectionView = UICollectionView(frame: frame, collectionViewLayout: layout)
collectionView?.dataSource = self
collectionView?.delegate = self
collectionView?.register(InterestsCell.self, forCellWithReuseIdentifier: "InterestsCell")
collectionView?.showsHorizontalScrollIndicator = false
view.addSubview(collectionView!)
}
I call configureCollectionView() from viewDidLayoutSubviews. This is the code I have in my collection view cell.
class InterestsCell: UICollectionViewCell {
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
let label: UILabel = {
let label = UILabel()
label.text = "Hello"
label.textColor = .white
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
func setupViews() {
contentView.backgroundColor = .red
contentView.addSubview(label)
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
}
Whenever I dequeue the cell, I get the correct size of the cell and the correct color. But when I go to set constraints on the label in my cell's setupViews function, the view controller will just not even open up altogether. If I don't set the constraints, the label is not there. I'm not sure what to do at this point and I would appreciate some help. Thank you!
I took a look at your above snippet and what I found is you haven't set the Frame you need to set the Frame of your UILabel
let label: UILabel = {
let label = UILabel()
label.frame = CGRect(x: 40, y: 100, width: self.view.frame.width, height: 30)
label.text = "Hello"
label.textColor = UIColor.red
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
Hope this help you
Since your project uses auto layout constraints you have to set them for the label:
func setupViews() {
contentView.backgroundColor = .red
contentView.addSubview(label)
label.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
}
Inside your InterestsCell class add the following code:
override func layoutSubviews() {
super.layoutSubviews()
setupViews()
}
instead of:
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
Hope this would work

How can I change my UICollectionView's Flow Layout to a vertical List with Horizontal Scrolling

Basically what I am trying to create is a table with three cells stacked on top of one another. But, if there are more than three cells, I want to be able to swipe left on the Collection View to show more cells. Here is a picture to illustrate.
Right now I have the cells arranged in a list but I cannot seem to change the scroll direction for some reason. - They still scroll vertically
Here is my current code for the Flow Layout:
Note: I'm not going to include the Collection View code that is in my view controller as I do not think it is relevant.
import Foundation
import UIKit
class HorizontalListCollectionViewFlowLayout: UICollectionViewFlowLayout {
let itemHeight: CGFloat = 35
func itemWidth() -> CGFloat {
return collectionView!.frame.width
}
override var itemSize: CGSize {
set {
self.itemSize = CGSize(width: itemWidth(), height: itemHeight)
}
get {
return CGSize(width: itemWidth(), height: itemHeight)
}
}
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint) -> CGPoint {
return collectionView!.contentOffset
}
override var scrollDirection: UICollectionViewScrollDirection {
set {
self.scrollDirection = .horizontal
} get {
return self.scrollDirection
}
}
}
If you have your cells sized correctly, Horizontal Flow Layout will do exactly what you want... fill down and across.
Here is a simple example (just set a view controller to this class - no IBOutlets needed):
//
// ThreeRowCViewViewController.swift
//
// Created by Don Mag on 6/20/17.
//
import UIKit
private let reuseIdentifier = "LabelItemCell"
class LabelItemCell: UICollectionViewCell {
// simple CollectionViewCell with a label
#IBOutlet weak var theLabel: UILabel!
let testLabel: UILabel = {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 14)
label.textColor = UIColor.black
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
override init(frame: CGRect) {
super.init(frame: frame)
addViews()
}
func addViews(){
addSubview(testLabel)
testLabel.leftAnchor.constraint(equalTo: self.leftAnchor, constant: 8.0).isActive = true
testLabel.centerYAnchor.constraint(equalTo: self.centerYAnchor, constant: 0.0).isActive = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
class ThreeRowCViewViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
// 3 gray colors for the rows
let cellColors = [
UIColor.init(white: 0.9, alpha: 1.0),
UIColor.init(white: 0.8, alpha: 1.0),
UIColor.init(white: 0.7, alpha: 1.0)
]
var theCodeCollectionView: UICollectionView!
override func viewDidLoad() {
super.viewDidLoad()
// height we'll use for the rows
let rowHeight = 30
// just picked a random width of 240
let rowWidth = 240
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
// horizontal collection view direction
layout.scrollDirection = .horizontal
// each cell will be the width of the collection view and our pre-defined height
layout.itemSize = CGSize(width: rowWidth - 1, height: rowHeight)
// no item spacing
layout.minimumInteritemSpacing = 0.0
// 1-pt line spacing so we have a visual "edge" (with horizontal layout, the "lines" are vertical blocks of cells
layout.minimumLineSpacing = 1.0
theCodeCollectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)
theCodeCollectionView.dataSource = self
theCodeCollectionView.delegate = self
theCodeCollectionView.register(LabelItemCell.self, forCellWithReuseIdentifier: reuseIdentifier)
theCodeCollectionView.showsVerticalScrollIndicator = false
// set background to orange, just to make it obvious
theCodeCollectionView.backgroundColor = .orange
theCodeCollectionView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(theCodeCollectionView)
// set collection view width x height to rowWidth x (rowHeight * 3)
theCodeCollectionView.widthAnchor.constraint(equalToConstant: CGFloat(rowWidth)).isActive = true
theCodeCollectionView.heightAnchor.constraint(equalToConstant: CGFloat(rowHeight * 3)).isActive = true
// center the collection view
theCodeCollectionView.centerXAnchor.constraint(equalTo: view.centerXAnchor, constant: 0.0).isActive = true
theCodeCollectionView.centerYAnchor.constraint(equalTo: view.centerYAnchor, constant: 0.0).isActive = true
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 12
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! LabelItemCell
cell.backgroundColor = cellColors[indexPath.row % 3]
cell.testLabel.text = "\(indexPath)"
return cell
}
}
I'll leave the "enable paging" part up to you :)

Resources