Auto Layout using layout anchors programmatically not working - ios

I am trying to add a stack view containing a UILabel at the top and a UICollectionView underneath. I am trying to constrain the stack view so that it takes up the full view, by anchoring it to all sides. When I run the app the UILabel appears and a slice of the collection view appears. The collection view says its width and height are both zero. Any help would be appreciated, thank you.
var collectionView: UICollectionView!
var titleLabel: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.view.translatesAutoresizingMaskIntoConstraints = false
let margins = self.view.layoutMarginsGuide
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
layout.itemSize = CGSize(width: self.collectionView.frame.width / 4, height: self.collectionView.frame.width / 4)
layout.minimumInteritemSpacing = self.collectionView.frame.width / 15
layout.minimumLineSpacing = self.collectionView.frame.width / 5
collectionView.backgroundColor = UIColor.black
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
titleLabel = UILabel()
titleLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.textAlignment = .center
titleLabel.numberOfLines = 1
titleLabel.font = UIFont.systemFont(ofSize: 22)
titleLabel.backgroundColor = UIColor.lightGray
titleLabel.text = "Challenges"
titleLabel.textColor = UIColor.red
let stackView = UIStackView(arrangedSubviews: [titleLabel, collectionView])
stackView.backgroundColor = UIColor.white
stackView.axis = .vertical
stackView.distribution = .fillEqually
stackView.alignment = .fill
stackView.spacing = 5
self.view.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false
//stackView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
//stackView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
stackView.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
stackView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
stackView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
stackView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
stackView.heightAnchor.constraint(equalTo: self.view.heightAnchor, multiplier: 1.0).isActive = true
}
UPDATE:
I took my code and ran it in a new single view application and it worked as expected. Because of this I think it is worth it to mention that I am trying to incorporate this into a sprite kit game and I present the view controller by doing this:
let root = self.view?.window?.rootViewController
var viewC = SelectionCollectionViewController()
root?.present(viewC, animated: false, completion: nil)
Are there special steps I need to take because this is done with sprite kit?

I believe below screen shot is the expected output.
You might not need UIStackView , You can directly add it to self.view.
Once added to self.view, you can set up constraints. You can print the item Size in viewDidLayoutSubviews
class ViewController: UIViewController {
var collectionView: UICollectionView!
var titleLabel: UILabel!
let collectionCellIdentifier:String = "collectionCellId"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
layout.sectionInset = UIEdgeInsets(top: 20, left: 10, bottom: 10, right: 10)
collectionView = UICollectionView(frame: CGRect.zero, collectionViewLayout: layout)
collectionView.delegate = self
collectionView.dataSource = self
collectionView.register(UICollectionViewCell.classForCoder(), forCellWithReuseIdentifier: collectionCellIdentifier)
collectionView.backgroundColor = UIColor.black
collectionView.dataSource = self
collectionView.delegate = self
collectionView.register(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
titleLabel = UILabel()
titleLabel.textAlignment = .center
titleLabel.numberOfLines = 1
titleLabel.font = UIFont.systemFont(ofSize: 22)
titleLabel.backgroundColor = UIColor.lightGray
titleLabel.text = "Challenges"
titleLabel.textColor = UIColor.red
titleLabel.translatesAutoresizingMaskIntoConstraints = false
collectionView.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(titleLabel)
self.view.addSubview(collectionView)
setUpConstraints()
}
func setUpConstraints(){
self.view.addConstraint(NSLayoutConstraint(item: self.titleLabel, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier:0, constant:50.0 ))
titleLabel.topAnchor.constraint(equalTo: self.view.topAnchor).isActive = true
titleLabel.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
titleLabel.widthAnchor.constraint(equalTo: self.view.widthAnchor).isActive = true
collectionView.topAnchor.constraint(equalTo: titleLabel.bottomAnchor).isActive = true
collectionView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
collectionView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
collectionView.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let flowLayout = (collectionView.collectionViewLayout as! UICollectionViewFlowLayout)
flowLayout.itemSize = CGSize(width: collectionView.frame.width / 4.0 , height: collectionView.frame.width / 4.0)
flowLayout.minimumInteritemSpacing = self.collectionView.frame.width / 15.0
flowLayout.minimumLineSpacing = self.collectionView.frame.width / 5.0
}
}
extension ViewController:UICollectionViewDataSource,UICollectionViewDelegate {
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: collectionCellIdentifier, for: indexPath)
cell.backgroundColor = UIColor.gray
return cell
}
}

I think you need to know what happen in these functions:
viewDidLoad
viewWillAppear
viewWillLayoutSubviews
viewDidLayoutSubviews
viewDidAppear
if you use autoLayout, when in viewDidLoad(), the frame is not confirmed, because the view will make an auto adjustment when in viewWillLayoutSubviews() and viewDidLayoutSubviews(), so I suggest you make these code in viewDidAppear(), and then you may see what you want!
Furthermore, if you use storyboard or nib, you need to do these in awakeFromNib()

Related

How can I disable Collection View but Header left enbled?

I need to disallow Collection View selection, but left CV's header enabled?
Both methods block header. How to enable it?
CollectionView.isUserInteractionEnabled = false
or
CollectionView.allowsSelection = false
Here is UICollectionReusableView:
final class HeaderCollectionReusableView: UICollectionReusableView {
override init(frame: CGRect) {
super.init(frame: .zero)
addSubView()
setupLayout()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
static let headerIdentifier = "HeaderCollectionReusableView"
private func addSubView() {
addSubview(collectionView)
}
public lazy var collectionView: UICollectionView = {
var flowLayout = UICollectionViewFlowLayout()
flowLayout.scrollDirection = .horizontal
flowLayout.itemSize = CGSize(width: UIScreen.main.bounds.size.width / 3.5, height: UIScreen.main.bounds.size.width / 3)
flowLayout.minimumLineSpacing = 12
flowLayout.sectionInset = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
var view = UICollectionView(frame: .zero, collectionViewLayout: flowLayout)
view.register(cell: CollectionViewCell.self)
view.backgroundColor = .clear
view.showsHorizontalScrollIndicator = false
view.showsVerticalScrollIndicator = false
view.contentInsetAdjustmentBehavior = .automatic
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
private func setupLayout() {
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: topAnchor),
collectionView.leadingAnchor.constraint(equalTo: leadingAnchor),
collectionView.trailingAnchor.constraint(equalTo: trailingAnchor),
collectionView.heightAnchor.constraint(equalToConstant: UIScreen.main.bounds.size.width / 3),
])
}
}
This is horizontal CV embedded in other vertical CV's header.
I need to disable vertical CV but left enabled horizontal CV in vertical CV' header )
To block I used CollectionView.isUserInteractionEnabled = false and it blocks everything even header.
I tried CollectionView.allowsSelection = false and it blocks CV and doesn't block header!
It works.
Before I just didn't pay attention that .allowSelection doesn't block header .

UIImageView not resizing as circle and UILabel not resizing within StackView and Custom Collection Cell

I am trying to resize my UIImageView as a circle, however; every time I try to resize the UIImageView, which is inside a StackView along with the UILabel, I keep on ending up with a more rectangular shape. Can someone show me where I am going wrong I have been stuck on this for days? Below is my code, and what it's trying to do is add the image with the label at the bottom, and the image is supposed to be round, and this is supposed to be for my collection view controller.
custom collection view cell
import UIKit
class CarerCollectionViewCell: UICollectionViewCell {
static let identifier = "CarerCollectionViewCell"
private let imageView: UIImageView = {
let imageView = UIImageView()
imageView.frame = CGRect(x: 0, y: 0, width: 20, height: 20);
//imageView.center = imageView.superview!.center;
imageView.contentMode = .scaleAspectFill
imageView.layer.borderWidth = 4
imageView.layer.masksToBounds = false
imageView.layer.borderColor = UIColor.orange.cgColor
imageView.layer.cornerRadius = imageView.frame.height / 2
return imageView
}()
private let carerNamelabel: UILabel = {
let carerNamelabel = UILabel()
carerNamelabel.layer.masksToBounds = false
carerNamelabel.font = .systemFont(ofSize: 12)
carerNamelabel.textAlignment = .center
carerNamelabel.layer.frame = CGRect(x: 0, y: 0, width: 50, height: 50);
return carerNamelabel
}()
private let stackView: UIStackView = {
let stackView = UIStackView()
stackView.layer.masksToBounds = false
stackView.axis = .vertical
stackView.alignment = .center
stackView.backgroundColor = .systemOrange
stackView.distribution = .fillProportionally
stackView.translatesAutoresizingMaskIntoConstraints = false
return stackView
}()
override init(frame: CGRect) {
super.init(frame: frame)
configureContentView()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
}
private func configureContentView() {
imageView.clipsToBounds = true
stackView.clipsToBounds = true
carerNamelabel.clipsToBounds = true
contentView.addSubview(stackView)
configureStackView()
}
private func configureStackView() {
allContraints()
stackView.addArrangedSubview(imageView)
stackView.addArrangedSubview(carerNamelabel)
}
private func allContraints() {
setStackViewConstraint()
}
private func setStackViewConstraint() {
stackView.widthAnchor.constraint(equalTo: contentView.widthAnchor).isActive = true
stackView.heightAnchor.constraint(equalTo: contentView.heightAnchor).isActive = true
stackView.centerXAnchor.constraint(equalTo: contentView.centerXAnchor).isActive = true
stackView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true
}
public func configureImage(with imageName: String, andImageName labelName: String) {
imageView.image = UIImage(named: imageName)
carerNamelabel.text = labelName
}
override func layoutSubviews() {
super.layoutSubviews()
stackView.frame = contentView.bounds
}
override func prepareForReuse() {
super.prepareForReuse()
imageView.image = nil
carerNamelabel.text = nil
}
}
Below here is my code for the CollectionViewControler
custom collection view
import UIKit
class CarerViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
private var collectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .vertical
layout.itemSize = CGSize(width: 120, height: 120)
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.register(CarerCollectionViewCell.self, forCellWithReuseIdentifier: CarerCollectionViewCell.identifier)
collectionView.showsVerticalScrollIndicator = false
collectionView.backgroundColor = .clear
return collectionView
}()
override func viewDidLoad() {
super.viewDidLoad()
collectionView.delegate = self
collectionView.dataSource = self
view.addSubview(collectionView)
collectionView.translatesAutoresizingMaskIntoConstraints = false
// Layout constraints for `collectionView`
NSLayoutConstraint.activate([
collectionView.widthAnchor.constraint(equalTo: view.widthAnchor),
collectionView.heightAnchor.constraint(lessThanOrEqualTo: view.heightAnchor, constant: 600),
collectionView.topAnchor.constraint(equalTo: view.topAnchor, constant: 200),
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor)
])
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 10
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CarerCollectionViewCell.identifier, for: indexPath) as! CarerCollectionViewCell
cell.configureImage(with: "m7opt04g_ms-dhoni-afp_625x300_06_July_20", andImageName: "IMAGE NO. 1")
return cell
}
}
Can somebody show or point to me what I am doing wrong, thank you
This is what I am trying to achieve
UIStackView could be tricky sometimes, you can embed your UIImageView in a UIView, and move your layout code to viewWillLayoutSubviews(), this also implys for the UILabel embed that also inside a UIView, so the containers UIViews will have a static frame for the UIStackViewto be layout correctly and whats inside them will only affect itself.

Self sizing UICollectionView with autolayout

I'm trying to figure out is it possible for UICollectionView to calculate it's own height using autolayout? My custom cells are built on autolayout and the UICollectionViewFlowLayout.automaticSize property for itemSize seems to be working, but the size of UICollectionView itself should be set. I believe that this is normal behavior, since the collection can have bigger size than it's cells, but maybe it is possible to make height of the content view of UICollectionView to be equal to cell with some insets?
Here is the code for test UIViewController with UICollectionView
class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {
var collectionView: UICollectionView?
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .green
let layout = UICollectionViewFlowLayout()
layout.estimatedItemSize = CGSize(width: UIScreen.main.bounds.width, height: 100)
layout.itemSize = UICollectionViewFlowLayout.automaticSize
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
if let collectionView = collectionView {
collectionView.showsHorizontalScrollIndicator = false
collectionView.isPagingEnabled = true
collectionView.register(CollectionViewCell.self,
forCellWithReuseIdentifier: "CollectionViewCell")
collectionView.backgroundColor = .clear
collectionView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(collectionView)
collectionView.delegate = self
collectionView.dataSource = self
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
collectionView.leftAnchor.constraint(equalTo: view.leftAnchor),
collectionView.rightAnchor.constraint(equalTo: view.rightAnchor),
// I want to get rid of this constraint
collectionView.heightAnchor.constraint(equalToConstant: 200)
])
}
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
5
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CollectionViewCell",
for: indexPath) as? CollectionViewCell else {
return UICollectionViewCell()
}
return cell
}
}
And for custom cell
final class CollectionViewCell: UICollectionViewCell {
var mainView = UIView()
var bigView: UIView = {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.backgroundColor = .yellow
return view
}()
var label: UILabel = {
let label = UILabel()
label.text = "Here is text"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
var anotherLabel: UILabel = {
let label = UILabel()
label.text = "Here may be no text"
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let inset: CGFloat = 16.0
override init(frame: CGRect) {
super.init(frame: frame)
addSubview(mainView)
mainView.translatesAutoresizingMaskIntoConstraints = false
mainView.backgroundColor = .white
addSubview(bigView)
addSubview(label)
addSubview(anotherLabel)
NSLayoutConstraint.activate([
mainView.widthAnchor.constraint(equalToConstant: UIScreen.main.bounds.width),
mainView.topAnchor.constraint(equalTo: topAnchor),
mainView.leftAnchor.constraint(equalTo: leftAnchor),
mainView.rightAnchor.constraint(equalTo: rightAnchor),
mainView.bottomAnchor.constraint(equalTo: bottomAnchor),
bigView.topAnchor.constraint(equalTo: mainView.topAnchor, constant: inset),
bigView.leftAnchor.constraint(equalTo: mainView.leftAnchor, constant: inset),
bigView.rightAnchor.constraint(equalTo: mainView.rightAnchor, constant: -inset),
bigView.bottomAnchor.constraint(equalTo: mainView.bottomAnchor, constant: -inset),
label.topAnchor.constraint(equalTo: bigView.topAnchor, constant: inset),
label.leftAnchor.constraint(equalTo: bigView.leftAnchor, constant: inset),
label.rightAnchor.constraint(equalTo: bigView.rightAnchor, constant: -inset),
anotherLabel.topAnchor.constraint(equalTo: label.bottomAnchor, constant: inset),
anotherLabel.leftAnchor.constraint(equalTo: bigView.leftAnchor, constant: inset),
anotherLabel.rightAnchor.constraint(equalTo: bigView.rightAnchor, constant: -inset),
anotherLabel.bottomAnchor.constraint(equalTo: bigView.bottomAnchor, constant: -inset)
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
And maybe someone, who knows the answer also could tell whether it's possible to later put this paging collection into UITalbleViewCell and make size of the cell change with selected item in the collection? I provide screenshot of the collection I'm trying to make:
Item's without second text label will have smaller height, than items on the picture
Screenshot
Solution 1:
Get collection view content size from collectionViewLayout :
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// Set your collection view height here.
let collectionHeight = self.yourCollectionView.collectionViewLayout.collectionViewContentSize.height
}
Solution 2:
Use KVO.
// Register observer
self.yourCollectionView.addObserver(self, forKeyPath: "contentSize", options: [.new, .old, .prior], context: nil)
#objc override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if keyPath == "contentSize" {
// content size changed. Set your collection view height here.
let contentSize = change?[NSKeyValueChangeKey.newKey] as? CGSize {
print("contentSize:", contentSize)
}
}
// Remove register observer
deinit {
self.yourCollectionView.removeObserver(self, forKeyPath: "contentSize")
}
Solution 3:
Assign this class to UICollectionView. If you set height constraint from storyboard then set and enable remove at runtime.
class DynamicCollectionView: UICollectionView {
override func layoutSubviews() {
super.layoutSubviews()
if !__CGSizeEqualToSize(bounds.size, self.intrinsicContentSize) {
self.invalidateIntrinsicContentSize()
}
}
override var intrinsicContentSize: CGSize {
var size = contentSize
size.height += (contentInset.top + contentInset.bottom)
size.width += (contentInset.left + contentInset.right)
return size
}
}

Layout constraints not working properly

I am having a lot of trouble getting this second custom class, which is another UICollectionView (green background) constraining to the bottom of the class above. I've tried all different sorts of constraints and constants of "0" etc. However it keeps positioning it on top of the other class. Does anyone have any ideas about what is happening?
Here is the screenshot:
class JobCell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
private let cellId = "jobCellId"
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
let jobLabel: UILabel = {
let label = UILabel()
label.backgroundColor = .green
label.text = "I WANT TO"
label.textColor = UIColor.rgb(red: 149, green: 149, blue: 149)
label.font = UIFont(name: "HelveticaNeue-Medium", size: 16)
label.textAlignment = .left
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
let jobsCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.backgroundColor = UIColor.red
collectionView.translatesAutoresizingMaskIntoConstraints = false
return collectionView
}()
func setupViews() {
backgroundColor = UIColor.clear
jobsCollectionView.dataSource = self
jobsCollectionView.delegate = self
jobsCollectionView.register(JobSingleCell.self, forCellWithReuseIdentifier: cellId)
addSubview(jobLabel)
addSubview(jobsCollectionView)
jobLabel.topAnchor.constraint(equalTo: topAnchor, constant: 0).isActive = true
jobLabel.leftAnchor.constraint(equalTo: leftAnchor, constant: 20).isActive = true
jobLabel.widthAnchor.constraint(equalToConstant: frame.width).isActive = true
jobLabel.heightAnchor.constraint(equalToConstant: 35).isActive = true
jobsCollectionView.topAnchor.constraint(equalTo: jobLabel.bottomAnchor, constant: 0).isActive = true
jobsCollectionView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
jobsCollectionView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
jobsCollectionView.heightAnchor.constraint(equalToConstant: frame.height).isActive = true
}
Here is the second blue cell:
class DayCell: UICollectionViewCell, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
private let dayCellId = "dayCellId"
override init(frame: CGRect) {
super.init(frame: frame)
setupViews()
}
let daysCollectionView: UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout)
collectionView.backgroundColor = UIColor.red
collectionView.translatesAutoresizingMaskIntoConstraints = false
return collectionView
}()
let dayLabel: UILabel = {
let label = UILabel()
label.backgroundColor = .green
label.text = "WHEN"
label.textColor = UIColor.rgb(red: 149, green: 149, blue: 149)
label.font = UIFont(name: "HelveticaNeue-Medium", size: 16)
label.textAlignment = .left
label.translatesAutoresizingMaskIntoConstraints = false
return label
}()
func setupViews() {
backgroundColor = UIColor.clear
addSubview(dayLabel)
dayLabel.topAnchor.constraint(equalTo: topAnchor).isActive = true
dayLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: 20).isActive = true
dayLabel.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
dayLabel.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true

Delegate Function Not Being Called

So I am trying to use protocols and delegates to connect two functions so I can perform some operation on a variable a collectionView in this case in a different file.
import Foundation
import UIKit
protocol EventCollectionCellDelegate: NSObjectProtocol {
func setupCollectionView(for eventCollectionView: UICollectionView?)
}
class EventCollectionCell:UICollectionViewCell {
weak var delegate: EventCollectionCellDelegate?
var eventArray = [EventDetails](){
didSet{
self.eventCollectionView.reloadData()
}
}
var enentDetails:Friend?{
didSet{
var name = "N/A"
var total = 0
seperator.isHidden = true
if let value = enentDetails?.friendName{
name = value
}
if let value = enentDetails?.events{
total = value.count
self.eventArray = value
seperator.isHidden = false
}
if let value = enentDetails?.imageUrl{
profileImageView.loadImage(urlString: value)
}else{
profileImageView.image = #imageLiteral(resourceName: "Tokyo")
}
self.eventCollectionView.reloadData()
setLabel(name: name, totalEvents: total)
}
}
let container:UIView={
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.layer.cornerRadius = 16
view.layer.borderColor = UIColor.lightGray.cgColor
view.layer.borderWidth = 0.3
return view
}()
//profile image view for the user
var profileImageView:CustomImageView={
let iv = CustomImageView()
iv.layer.masksToBounds = true
iv.layer.borderColor = UIColor.lightGray.cgColor
iv.layer.borderWidth = 0.3
iv.translatesAutoresizingMaskIntoConstraints = false
return iv
}()
//will show the name of the user as well as the total number of events he is attending
let labelNameAndTotalEvents:UILabel={
let label = UILabel()
label.textColor = .black
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
return label
}()
let seperator:UIView={
let view = UIView()
view.backgroundColor = .lightGray
view.translatesAutoresizingMaskIntoConstraints = false
return view
}()
//collectionview that contains all of the events a specific user will be attensing
let flow = UICollectionViewFlowLayout()
lazy var eventCollectionView = UICollectionView(frame: .zero, collectionViewLayout: flow)
// var eventCollectionView:UICollectionView?
override init(frame: CGRect) {
super.init(frame: frame)
self.setUpCell()
self.setupCollectionView(for: eventCollectionView)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setupCollectionView(for eventCollectionView: UICollectionView?){
delegate?.setupCollectionView(for: eventCollectionView)
}
}
This is the file that creates a collectionViewCell with a collectionView in it. I am trying to perform some operation on that collectionView using the delegate pattern. My problem is that the delegate function is never called in the accompanying viewController. I feel like I have done everything right but nothing happens in the accompanying vc. Anyone notice what could possibly be wrong.
I have shown the code for the VC below
class FriendsEventsView: UIViewController,UICollectionViewDelegate,UICollectionViewDataSource,UICollectionViewDelegateFlowLayout,EventCollectionCellDelegate {
var friends = [Friend]()
var followingUsers = [String]()
var height:CGFloat = 0
var notExpandedHeight : CGFloat = 50
var isExpanded = [Bool]()
//so this is the main collectonview that encompasses the entire view
lazy var mainCollectionView:UICollectionView={
// the flow layout which is needed when you create any collection view
let flow = UICollectionViewFlowLayout()
//setting the scroll direction
flow.scrollDirection = .vertical
//setting space between elements
let spacingbw:CGFloat = 5
flow.minimumLineSpacing = spacingbw
flow.minimumInteritemSpacing = 0
//actually creating collectionview
let cv = UICollectionView(frame: .zero, collectionViewLayout: flow)
//register a cell for that collectionview
cv.register(EventCollectionCell.self, forCellWithReuseIdentifier: "events")
cv.translatesAutoresizingMaskIntoConstraints = false
//changing background color
cv.backgroundColor = .white
//sets the delegate of the collectionView to self. By doing this all messages in regards to the collectionView will be sent to the collectionView or you.
//"Delegates send messages"
cv.delegate = self
//sets the datsource of the collectionView to you so you can control where the data gets pulled from
cv.dataSource = self
//sets positon of collectionview in regards to the regular view
cv.contentInset = UIEdgeInsetsMake(spacingbw, 0, spacingbw, 0)
return cv
}()
lazy var eventCollectionView:UICollectionView={
let flow = UICollectionViewFlowLayout()
flow.scrollDirection = .vertical
let spacingbw:CGFloat = 5
flow.minimumLineSpacing = 0
flow.minimumInteritemSpacing = 0
let cv = UICollectionView(frame: .zero, collectionViewLayout: flow)
//will register the eventdetailcell
cv.translatesAutoresizingMaskIntoConstraints = false
cv.backgroundColor = .white
cv.register(EventDetailsCell.self, forCellWithReuseIdentifier: "eventDetails")
cv.delegate = self
cv.dataSource = self
cv.contentInset = UIEdgeInsetsMake(spacingbw, 0, spacingbw, 0)
cv.showsVerticalScrollIndicator = false
cv.bounces = false
return cv
}()
func setupCollectionView(for eventCollectionView: UICollectionView?) {
print("Attempting to create collectonView")
eventCollectionView?.backgroundColor = .blue
}
//label that will be displayed if there are no events
let labelNotEvents:UILabel={
let label = UILabel()
label.textColor = .lightGray
label.translatesAutoresizingMaskIntoConstraints = false
label.numberOfLines = 0
label.font = UIFont.italicSystemFont(ofSize: 14)
label.text = "No events found"
label.isHidden = true
return label
}()
override func viewDidLoad() {
super.viewDidLoad()
//will set up all the views in the screen
self.setUpViews()
self.navigationItem.rightBarButtonItem = UIBarButtonItem(image: #imageLiteral(resourceName: "close_black").withRenderingMode(.alwaysOriginal), style: .done, target: self, action: #selector(self.goBack))
}
func setUpViews(){
//well set the navbar title to Friends Events
self.title = "Friends Events"
view.backgroundColor = .white
//adds the main collection view to the view and adds proper constraints for positioning
view.addSubview(mainCollectionView)
mainCollectionView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor, constant: 0).isActive = true
mainCollectionView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor, constant: 0).isActive = true
mainCollectionView.rightAnchor.constraint(equalTo: view.rightAnchor, constant: 0).isActive = true
mainCollectionView.leftAnchor.constraint(equalTo: view.leftAnchor, constant: 0).isActive = true
//adds the label to alert someone that there are no events to the collectionview and adds proper constrains for positioning
mainCollectionView.addSubview(labelNotEvents)
labelNotEvents.centerYAnchor.constraint(equalTo: mainCollectionView.centerYAnchor, constant: 0).isActive = true
labelNotEvents.centerXAnchor.constraint(equalTo: mainCollectionView.centerXAnchor, constant: 0).isActive = true
//will fetch events from server
self.fetchEventsFromServer()
}
// MARK: CollectionView Datasource for maincollection view
//woll let us know how many cells are being displayed
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
print(friends.count)
isExpanded = Array(repeating: false, count: friends.count)
return friends.count
}
//will control the size of the cell that is displayed in the containerview
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
height = 100
let event = friends[indexPath.item]
if let count = event.events?.count,count != 0{
height += (CGFloat(count*40)+10)
}
return CGSize(width: collectionView.frame.width, height: height)
}
//will do the job of effieicently creating cells for the eventcollectioncell
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "events", for: indexPath) as! EventCollectionCell
cell.delegate = self
cell.enentDetails = friends[indexPath.item]
cell.eventCollectionView = eventCollectionView
return cell
}
}
I have cut the code down to what I believe is needed to answer the question for simplicity. Any help is appreciated
You set delegate after setupCollectionView. In your case, you can't call setupCollectionView before you set delegate, because setupCollectionView called in init

Resources