UICollectionView cell ignores UICollectionViewDelegateFlowLayout - sizeForItemAt - ios

I am trying to layout the size of my collectionViewCell so that in each row there are 7 cells (easy right?).
The cell is very simple, it only has a UILabel with top, left, bottom and right constraints of 0.
I have setup the sizeForItemAt method as below, made sure my controller is a collectionViewDelegateFlowLayout, collectionViewDelegate and collectionViewDataSource, and that collectionview.delegate and .datasource = self.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let safeScreenWidth = self.view.frame.size.width - 30
let width: CGFloat = (safeScreenWidth / 7)
let height: CGFloat = 40.0
return CGSize(width: width, height: height)
}
The method is called correctly (checked with break points and print()) however the cell decides to totally ignore the size given and comes out with a size just enough to contain its label's text (if the label's text is empty the app crashes for "Invalid parameter not satisfying: !CGSizeEqualToSize(size, CGSizeZero)").
I tried setting different sizes such width = 200, height = 200; but nothing changes the cell is always very small, as I said, just enough to fit its label's text.
A quick solve is setting height and width constraints for the label in cellForItemAt, but I want to understand why sizeForItemAt does not work.

For some reason, automatic estimated size has bigger priority, than calculated in sizeForItemAt method.
Try to set collectionViews Estimate Size to None

Related

How to resize UICollectionViewCell based on device screen

I have a UICollectionView with a custom cell, however, I am trying to impose constraints on the UICollectionView, so it is always half the width of the screen and half the height of the screen. The one issue I continually encounter is that while the UICollectionView changes according to what device the app is deployed on, the UICollectionViewCells hold the exact same pixel width and height dimensions. This is the code I have tried to implement to make each cell the same height and width as the CollectionView.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let height = collectionView.frame.height
let width = collectionView.frame.width
return CGSize(width: width, height: height)
}
This code, however, doesn't work as the size of the cells are simply the values that are specified in the size inspector for the UICollectionView.
I'm unable to figure out what I am doing wrong here with my code. Thank you very much in advance for your help.
The issue is your collection view cell size is fixed always. So the cell size is not adjust according to screen size.Use view frame size.(remove values from size inspector)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: view.frame.width, height: view.frame.height)
}

Calculating cell width in UICollectionView inside ContainerView

I have a UICollectionView and I have implemented the delegate to calculate the width of my cells for 0 spacing between cells.
It works great on its own, but when I have it inside a container view less than the size of the device, iOS incorrectly works out the spacing between the cells adding a horizontal space I don't want.
I have verified the width I am using to calculate the cell size is correct, so I'm not sure what is causing the problem.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let widthPerItem = view.frame.width / itemsPerRow
return CGSize(width: widthPerItem, height: 60)
}
You are calculating your cell size based upon the size of the view. Since the collectionView doesn't take up the full width of the screen, you are getting the incorrect value. Instead, you should base your calculation on the width of the collectionView itself.
Use the bounds of the collectionView instead of the frame of the view:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let widthPerItem = collectionView.bounds.width / itemsPerRow
return CGSize(width: widthPerItem, height: 60)
}
Ok, the problem was actually related to my uicollectionviewcontroller not correctly sizing to it's parent container view. Changing to a uiviewcontroller with an embedded uicollectionview plus constraints fixed the problem.

Access custom cell from XIB in UICollectionViewController for sizeForItemAtIndexPath

I have spent 3 days of searching and reading. In my IOS app I have a custom Cell for UICollectionView with xib File. In this custom cell I have 3 labels, images and buttons. 1 label from it is in the middle and always gets different sizes because it's multiline.
So I must calculate all items height. It's not the problem but the problem is only with this one multiline label. So I want calculate the size for each cell and get the size for sizeForItemAtIndexPath in UICollectionViewController.
After 3 days I think I cannot access this. Can I do this from the custom cell class? If yes, how? If I can access it in UICollectionViewController, how?
//MARK: - CollectionView Flow Layout
extension PhotosCollectionViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
let viewSize = super.view.bounds.size
let spacing: CGFloat = 0.5
let width = (viewSize.width) - spacing - 10
/*
Here I need my cell with label name "Beschreibungstext"
to calculate the hight from the label with help from rectangle.
return CGSize(width: width, height: customhight)
*/
return CGSize(width: width, height: CGFloat(400))
}
}

Auto Layout Collection view according to various screen sizes

I'm using a collection view inside a normal view controller using the collection view delegate and data source. I'm using the sizeForItemAtIndexPath but it doesn't resize the cell.
let screenSize: CGRect = UIScreen.main.bounds
func collectionView(_collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize
{
return CGSize(width: screenSize.width / 3, height: screenSize.width / 3)
}
The collection view is assigned the constraints using autoLayout properly.
How it looks in iPhone5
How it should look
I know the estimatedItemSize is used but I'm unable to use it since this is not a UICollectionViewController. Thanks for any suggestion?
Make sure that:
Confirming to UICollectionViewDelegateFlowLayout.
collectionView's width = screen's width.
Min Spacing for cells is zero. You can change it from the Interface Builder (Select the collectionView -> show size inspector -> set min spacing to 0), or by implementing minimumInteritemSpacingForSectionAt returning zero.
I hope that answered your question.

Auto Layout size of CollectionViewCell in relation to CollectionView

I have a CollectionViewCell placed in a CollectionView. The size of the CollectionView is set via Auto Layout and can change at times.
I want to (programmatically) set constraints on my CollectionView, so that the size of the CollectionViewCell is responsive to the size of the CollectionView (Say the width of the Cell is equal to the width of the CollectionView-100 and the height should be equal).
How can I declare constraints between the Cell and the CollectionView?
When, where and how do set those constraints? Do I have to call setNeedsLayout on the Cells when the size of the CollectionView changes?
I searched for this quite long and all I found was always about changing the size of the Cell according to its content – that’s not what I am trying to do. The only hint that I got is that I might have to subclass CollectionViewLayout – but I’m not sure about that.
Any help is appreciated!
You cannot achieve this using constraints, but you can easily do this using UICollectionViewDelegate's sizeForItemAtIndexPath method. Example:
func collectionView(collectionView: UICollectionView,
layout collectionViewLayout: UICollectionViewLayout,
sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
return CGSize(width: collectionView.frame.size.width / 2, height: collectionView.frame.size.height/ 2)
}
And after changing the collectionView size all you need to do is call its reloadData method.
I can suggest for you 2 ways how to do this:
In your UIViewController try to set the collectionViewLayout property in viewDidLayoutSubviews method. I'm not sure if it works when screen orientation will change.
- (void)viewDidLayoutSubviews
{
UICollectionViewFlowLayout *flow = YOUR_COLLECTION_VIEW.collectionViewLayout;
float width = CGRectGetWidth(YOUR_COLLECTION_VIEW.frame)-100.f;
float height = CGRectGetHeight(YOUR_COLLECTION_VIEW.frame);
YOUR_COLLECTION_VIEW.collectionViewLayout = flow;
}
If that doesn't work, then I'm 100% sure that it will work if you subclass the collectionView and insert the same code but in (void)layoutSubviews
Set the cell height and get the collection view height in UICollectionViewDelegateFlowLayout sizeForItemAt method. You can set the cell size based on a whole number or multiply as a percentage if that's more appropriate.
func collectionView(_ collectionView: UICollectionView, layout
collectionViewLayout: UICollectionViewLayout, sizeForItemAt
indexPath: IndexPath) -> CGSize {
let heigh = collectionView.frame.height
let widthOfCell = collectionView.frame.width - 100 // OP request
return CGSize(width: width, height: height)
}

Resources