Adding UILabel/UIImageView to UIContentViewCell disturbs it's size - ios

I have a UICollectionViewCell defined in storyboard which has a UILabel added to it's contentView. Collection view uses a flow layout and I return a fixed size of cell in flowlayout delegate as follows:
let sizeOfItem = CGFloat(210.0)
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: sizeOfItem, height: sizeOfItem)
}
I added the following constraint for UILabel in storyboard and the cell automatically starts resizing itself to match the text size in UILabel. This is not what I want. I want the cell to be fixed size and label to autoshrink instead.
I even tried setting contentHuggingPriority of label to lowest value (i.e. 1). This stops the cell from auto-shrinking if the text in label is small. But still the cell grows when the text is big. I don't want this to happen either. I want the cell to be fixed size as returned by sizeForItem in delegate and the label to adapt it's font size.
EDIT: I also set contentCompressionProperty to lowest and it then works. But I am wondering what is the right way to fix this kind of scenario where contentView does not depend on subviews.
EDIT 2: The problem also appears when having UIImageView in contentView and the image is bigger or smaller than defined cell size. Setting intrinsic content size of UIImageView does not help.

To get the exact cell size as specified in the delegate method, you can't use an equal width constraint since then it will be a dynamic-size cell.

Related

CollectionViewCell inside of presented ViewController in Xcode 11 distorting cell size

I have a UIViewController that I present from my main screen, which with Xcode 11 new presentation style, is dismissable by dragging down (modal style). Inside of this view controller there is a collection view with a full width and full height cell inside of which there is an imageView that occupies the whole cell.
My collectionView is meant to be paginated, and has a method sizeForItemAt to make the cell the size of the cell:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: collectionView.bounds.width, height: collectionView.bounds.height)
}
What happens is that when I scroll past the collection view's content bounds, the cell get completely distorted and I get the following error:
The behavior of the UICollectionViewFlowLayout is not defined because the item height must be less than the height of the UICollectionView minus the section insets top and bottom values, minus the content insets top and bottom values.
I have read a few posts about it, and I've tried a few things:
Presenting the UIViewController as full screen (it still distorts the cell when part the horizontal bounds of the collView)
Changing the content inset adjustment behavior of the collection view to ".never"
Removing the bounce
Taking out the image (it does work, as it doesn't distort the cell, but defeats the purpose of design)
Changed constraints of an image from equal to superview to equal height and width to cell and centered in the cell
I'm really racking my brain as to what can be going wrong, to the point that I might be thinking it might be a bug with Xcode 11's presentation style, however, I have no way to be sure of this.
What might be going wrong?

Why on Xcode 11, UICollectionViewCell changes size as soon as you scroll (I already set size in sizeForItem AtIndexPath:)?

I have collectionview inside tableview cell and I use nib for my collection view cell (in which I use autolayout for my imageview and labels and it is on Freeform mode). I'm setting cell size in tableviewcell class which is handling the delegate for collectionview inside it by this method:
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: 200, height :150)
}
It always works but after Xcode 11 it doesn't.
I have the same problem. And my solution is to change the Estimate size to None in the Xcode 11.
You set collectionview Estimate size to None in Xcode 11. The reason for this is that cells in a UICollectionView can now self-size with Auto Layout constrained views in the canvas. To opt into the behavior for existing collection views, enable “Automatic” for the collection view’s estimated size, and “Automatic” for cell’s size from the Size inspector.
If deploying before iOS 13, you can activate self sizing collection view cells by calling performBatchUpdates(_:completion:) during viewDidLoad()
Ref:
https://developer.apple.com/documentation/xcode_release_notes/xcode_11_release_notes
As Anh Tuan said in another answer here, you just need to change the Estimate Size to none in the Size Inspector of the Collection View from the Storyboard.
But if you wanna do this programmatically, you can try this code:
let layout = myCollectionViewReferenceHere.collectionViewLayout as! UICollectionViewFlowLayout
layout.estimatedItemSize = .zero
This problem is coming in Xcode 11. Go to the attribute inspector and change the estimateSize to None. will fix every thing.

How to increase the UICollectionview Cell Size equal to Screen Size in swift 4.2?

How to increase the UICollectionView Cell width & height equal to screen in swift 4.2 ?
Provided your UICollectionViewCell has a subview of UIImageView that is anchored to fill it completely(i.e. UIImageView is anchored UICollectionViewCell in top, bottom, left and right manner).
The following method can be used to size the UICollectionViewCell in accordance to the screen screen holding it, this will automatically result in the UIImageView being as big as the screen itself.
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return self.collectionView.bounds.size //to ensure that this works as intended set self.collectionView size be the screen size.
}
Please note that the UICollectionView is big enough to hold the size of the UICollectionViewCell that you seek.
You need to change your cell size to fit the collectionview. Add this in viewDidLoad
if let flow = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
flow.itemSize = self.collectionView.frame.size
}

Dynamic Buttons in UIScrollView with Equal width and height

I want to display list of buttons in scrollview with dynamic height based on screen size. I can able to do this in UIView, but when I applied same auto layout approach in UIScrollView, it's not increasing the size of buttons. So please guide me How to increase the button size in UIScrollView based on screen size.
if button is dynamic and may be increase and decrease in future than you Should use CollectionView not ScrollView.
Drag CollectionView into ViewController.
Drag Cell in CollectionView.
Add button(or label based on your requirement) In Cell.set button(leading,trailing,top,bottom) == Cell(leading,trailing,top,bottom)
Write dataSource and delegate methods and UICollectionViewDelegateFlowLayout methods.
and change Following Methods to increase button height According To Screen
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
return CGSize(width: self.view.bounds.width/2, height: self.view.bounds.height*0.15)
}

Image view added in collection view cell doesn't apply added constraints

I've added an image to UICollectionViewCell and added constraints like the following image.
Constraints:
Width of ImageView = Width of Cell
Height of ImageView = Height of Cell
Align ImageView vertically in container (Cell)
Align ImageView horizontally in container (Cell)
I'm deciding the cell size at run time using the UICollectionViewDelegate method.
func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize
{
// calculating cell size and returning it
}
Issue:
In the cellForItemAtIndexPath method, when I checked the cell size and image view size both have different values.
Cell {w:82.0, h:145.77}, ImageView {w:380.0,h:170}. Image has the same frame size which I set on storyboard. It is not adjusting based on the constraints.
Is there anyway I can ensure that it have the same size of my cell ?
Current Fix: (?)
cell.imageView.frame = cell.bounds
But it doesn't make any sense. Why I need to set the size explicitly, why the constraints not applied?
Check this answer by Marius Soutier: UICollectionView: different size items is not calculated on reused items
The comment below his answer is probably the solution you are looking for.
Basically, you have to call reloadData before you return your CGSize from sizeForItemAtIndexPath:.

Resources