Autosizing Cells: Cell Width Equal to the Collectionview

AutoSizing cells: cell width equal to the CollectionView

To implement self-sizing collection view cells you need to do two things:

  1. Specify estimatedItemSize on UICollectionViewFlowLayout
  2. Implement preferredLayoutAttributesFitting(_:) on your cell

1. Specifying estimatedItemSize on UICollectionViewFlowLayout

The default value of this property is CGSizeZero. Setting it to any other value causes the collection view to query each cell for its actual size using the cell’s preferredLayoutAttributesFitting(_:) method. If all of your cells are the same height, use the itemSize property, instead of this property, to specify the cell size instead.

This is just an estimate which is used to calculate the content size of the scroll view, set it to something sensible.

let collectionViewFlowLayout = UICollectionViewFlowLayout()
collectionViewFlowLayout.estimatedItemSize = CGSize(width: collectionView.frame.width, height: 100)

2. Implement preferredLayoutAttributesFitting(_:) on your UICollectionViewCell subclass

override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
let autoLayoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes)

// Specify you want _full width_
let targetSize = CGSize(width: layoutAttributes.frame.width, height: 0)

// Calculate the size (height) using Auto Layout
let autoLayoutSize = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: UILayoutPriority.required, verticalFittingPriority: UILayoutPriority.defaultLow)
let autoLayoutFrame = CGRect(origin: autoLayoutAttributes.frame.origin, size: autoLayoutSize)

// Assign the new size to the layout attributes
autoLayoutAttributes.frame = autoLayoutFrame
return autoLayoutAttributes
}

UICollectionView Self Sizing Cells with Auto Layout

This answer is outdated from iOS 14 with the addition of compositional layouts. Please consider updating the new API

Updated for Swift 5

preferredLayoutAttributesFittingAttributes renamed to preferredLayoutAttributesFitting and use auto sizing



Updated for Swift 4

systemLayoutSizeFittingSize renamed to systemLayoutSizeFitting



Updated for iOS 9

After seeing my GitHub solution break under iOS 9 I finally got the time to investigate the issue fully. I have now updated the repo to include several examples of different configurations for self sizing cells. My conclusion is that self sizing cells are great in theory but messy in practice. A word of caution when proceeding with self sizing cells.

TL;DR

Check out my GitHub project


Self sizing cells are only supported with flow layout so make sure thats what you are using.

There are two things you need to setup for self sizing cells to work.

#1. Set estimatedItemSize on UICollectionViewFlowLayout

Flow layout will become dynamic in nature once you set the estimatedItemSize property.

self.flowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize

#2. Add support for sizing on your cell subclass

This comes in 2 flavours; Auto-Layout or custom override of preferredLayoutAttributesFittingAttributes.

Create and configure cells with Auto Layout

I won't go to in to detail about this as there's a brilliant SO post about configuring constraints for a cell. Just be wary that Xcode 6 broke a bunch of stuff with iOS 7 so, if you support iOS 7, you will need to do stuff like ensure the autoresizingMask is set on the cell's contentView and that the contentView's bounds is set as the cell's bounds when the cell is loaded (i.e. awakeFromNib).

Things you do need to be aware of is that your cell needs to be more seriously constrained than a Table View Cell. For instance, if you want your width to be dynamic then your cell needs a height constraint. Likewise, if you want the height to be dynamic then you will need a width constraint to your cell.

Implement preferredLayoutAttributesFittingAttributes in your custom cell

When this function is called your view has already been configured with content (i.e. cellForItem has been called). Assuming your constraints have been appropriately set you could have an implementation like this:

//forces the system to do one layout pass
var isHeightCalculated: Bool = false

override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
//Exhibit A - We need to cache our calculation to prevent a crash.
if !isHeightCalculated {
setNeedsLayout()
layoutIfNeeded()
let size = contentView.systemLayoutSizeFitting(layoutAttributes.size)
var newFrame = layoutAttributes.frame
newFrame.size.width = CGFloat(ceilf(Float(size.width)))
layoutAttributes.frame = newFrame
isHeightCalculated = true
}
return layoutAttributes
}

NOTE On iOS 9 the behaviour changed a bit that could cause crashes on your implementation if you are not careful (See more here). When you implement preferredLayoutAttributesFittingAttributes you need to ensure that you only change the frame of your layout attributes once. If you don't do this the layout will call your implementation indefinitely and eventually crash. One solution is to cache the calculated size in your cell and invalidate this anytime you reuse the cell or change its content as I have done with the isHeightCalculated property.

Experience your layout

At this point you should have 'functioning' dynamic cells in your collectionView. I haven't yet found the out-of-the box solution sufficient during my tests so feel free to comment if you have. It still feels like UITableView wins the battle for dynamic sizing IMHO.

##Caveats
Be very mindful that if you are using prototype cells to calculate the estimatedItemSize - this will break if your XIB uses size classes. The reason for this is that when you load your cell from a XIB its size class will be configured with Undefined. This will only be broken on iOS 8 and up since on iOS 7 the size class will be loaded based on the device (iPad = Regular-Any, iPhone = Compact-Any). You can either set the estimatedItemSize without loading the XIB, or you can load the cell from the XIB, add it to the collectionView (this will set the traitCollection), perform the layout, and then remove it from the superview. Alternatively you could also make your cell override the traitCollection getter and return the appropriate traits. It's up to you.



UICollectionView, full width cells, allow autolayout dynamic height?

1. Solution for iOS 13+

With Swift 5.1 and iOS 13, you can use Compositional Layout objects in order to solve your problem.

The following complete sample code shows how to display multiline UILabel inside full-width UICollectionViewCell:

CollectionViewController.swift

import UIKit

class CollectionViewController: UICollectionViewController {

let items = [
[
"Lorem ipsum dolor sit amet.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
],
[
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
],
[
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"Lorem ipsum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.",
]
]

override func viewDidLoad() {
super.viewDidLoad()

let size = NSCollectionLayoutSize(
widthDimension: NSCollectionLayoutDimension.fractionalWidth(1),
heightDimension: NSCollectionLayoutDimension.estimated(44)
)
let item = NSCollectionLayoutItem(layoutSize: size)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: size, subitem: item, count: 1)

let section = NSCollectionLayoutSection(group: group)
section.contentInsets = NSDirectionalEdgeInsets(top: 10, leading: 10, bottom: 10, trailing: 10)
section.interGroupSpacing = 10

let headerFooterSize = NSCollectionLayoutSize(
widthDimension: .fractionalWidth(1.0),
heightDimension: .absolute(40)
)
let sectionHeader = NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: headerFooterSize,
elementKind: "SectionHeaderElementKind",
alignment: .top
)
section.boundarySupplementaryItems = [sectionHeader]

let layout = UICollectionViewCompositionalLayout(section: section)
collectionView.collectionViewLayout = layout
collectionView.register(CustomCell.self, forCellWithReuseIdentifier: "CustomCell")
collectionView.register(HeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderView")
}

override func numberOfSections(in collectionView: UICollectionView) -> Int {
return items.count
}

override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items[section].count
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.label.text = items[indexPath.section][indexPath.row]
return cell
}

override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderView", for: indexPath) as! HeaderView
headerView.label.text = "Header"
return headerView
}

override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
coordinator.animate(alongsideTransition: { context in
self.collectionView.collectionViewLayout.invalidateLayout()
}, completion: nil)
}

}

HeaderView.swift

import UIKit

class HeaderView: UICollectionReusableView {

let label = UILabel()

override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .magenta

addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

}

CustomCell.swift

import UIKit

class CustomCell: UICollectionViewCell {

let label = UILabel()

override init(frame: CGRect) {
super.init(frame: frame)

label.numberOfLines = 0
backgroundColor = .orange
contentView.addSubview(label)

label.translatesAutoresizingMaskIntoConstraints = false
label.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

}

Expected display:

Sample Image


2. Solution for iOS 11+

With Swift 5.1 and iOS 11, you can subclass UICollectionViewFlowLayout and set its estimatedItemSize property to UICollectionViewFlowLayout.automaticSize (this tells the system that you want to deal with autoresizing UICollectionViewCells). You'll then have to override layoutAttributesForElements(in:) and layoutAttributesForItem(at:) in order to set cells width. Lastly, you'll have to override your cell's preferredLayoutAttributesFitting(_:) method and compute its height.

The following complete code shows how to display multiline UILabel inside full-width UIcollectionViewCell (constrained by UICollectionView's safe area and UICollectionViewFlowLayout's insets):

CollectionViewController.swift

import UIKit

class CollectionViewController: UICollectionViewController {

let items = [
[
"Lorem ipsum dolor sit amet.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris. Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
],
[
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
],
[
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt.",
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"Lorem ipsum. Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris.",
]
]
let customFlowLayout = CustomFlowLayout()

override func viewDidLoad() {
super.viewDidLoad()

customFlowLayout.sectionInsetReference = .fromContentInset // .fromContentInset is default
customFlowLayout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
customFlowLayout.minimumInteritemSpacing = 10
customFlowLayout.minimumLineSpacing = 10
customFlowLayout.sectionInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
customFlowLayout.headerReferenceSize = CGSize(width: 0, height: 40)

collectionView.collectionViewLayout = customFlowLayout
collectionView.contentInsetAdjustmentBehavior = .always
collectionView.register(CustomCell.self, forCellWithReuseIdentifier: "CustomCell")
collectionView.register(HeaderView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderView")
}

override func numberOfSections(in collectionView: UICollectionView) -> Int {
return items.count
}

override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items[section].count
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "CustomCell", for: indexPath) as! CustomCell
cell.label.text = items[indexPath.section][indexPath.row]
return cell
}

override func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: "HeaderView", for: indexPath) as! HeaderView
headerView.label.text = "Header"
return headerView
}

}

CustomFlowLayout.swift

import UIKit

final class CustomFlowLayout: UICollectionViewFlowLayout {

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
let layoutAttributesObjects = super.layoutAttributesForElements(in: rect)?.map{ $0.copy() } as? [UICollectionViewLayoutAttributes]
layoutAttributesObjects?.forEach({ layoutAttributes in
if layoutAttributes.representedElementCategory == .cell {
if let newFrame = layoutAttributesForItem(at: layoutAttributes.indexPath)?.frame {
layoutAttributes.frame = newFrame
}
}
})
return layoutAttributesObjects
}

override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
guard let collectionView = collectionView else {
fatalError()
}
guard let layoutAttributes = super.layoutAttributesForItem(at: indexPath)?.copy() as? UICollectionViewLayoutAttributes else {
return nil
}

layoutAttributes.frame.origin.x = sectionInset.left
layoutAttributes.frame.size.width = collectionView.safeAreaLayoutGuide.layoutFrame.width - sectionInset.left - sectionInset.right
return layoutAttributes
}

}

HeaderView.swift

import UIKit

class HeaderView: UICollectionReusableView {

let label = UILabel()

override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = .magenta

addSubview(label)
label.translatesAutoresizingMaskIntoConstraints = false
label.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true
label.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

}

CustomCell.swift

import UIKit

class CustomCell: UICollectionViewCell {

let label = UILabel()

override init(frame: CGRect) {
super.init(frame: frame)

label.numberOfLines = 0
backgroundColor = .orange
contentView.addSubview(label)

label.translatesAutoresizingMaskIntoConstraints = false
label.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor).isActive = true
label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor).isActive = true
label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
let layoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes)
layoutIfNeeded()
layoutAttributes.frame.size = systemLayoutSizeFitting(UIView.layoutFittingCompressedSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
return layoutAttributes
}

}

Here are some alternative implementations for preferredLayoutAttributesFitting(_:):

override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
let targetSize = CGSize(width: layoutAttributes.frame.width, height: 0)
layoutAttributes.frame.size = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel)
return layoutAttributes
}
override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
label.preferredMaxLayoutWidth = layoutAttributes.frame.width
layoutAttributes.frame.size.height = contentView.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize).height
return layoutAttributes
}

Expected display:

Sample Image

How to set collectionview cell width based on content?

instead of calling sizeforitem

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {

return CGSize(width: 100, height : 100)
}

You can set layout properties to auto resizing according to label content

let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 0
layout.minimumInteritemSpacing = 0
layout.estimatedItemSize = CGSize(width: 100, height: 30)

Set the size of a collectionView with cell of different width, in a horizontal scrolling

You can use constraints to make your cells "auto-sizing" and you won't have to do any manual calculating of the text / label sizes.

Give this a try. Of course, it will need modifications to suit your needs, but should give you something to work with (Edit: I updated my code to more closely match your approach):

//
// MenuBarViewController.swift
//

import UIKit

private let reuseIdentifier = "MyASCell"

class MyMenuCell: UICollectionViewCell {

override init(frame: CGRect) {
super.init(frame: frame)

setupViews()
}

override var isSelected: Bool {
didSet {
labelTitre.textColor = isSelected ? UIColor.black : .lightGray
}
}

let labelTitre : UILabel = {
let label = UILabel()
label.textColor = .gray
return label
}()

func setupViews() {
backgroundColor = UIColor.white
addSubview(labelTitre)

labelTitre.translatesAutoresizingMaskIntoConstraints = false

// set constraints to use the label's intrinsic size for auto-sizing
// we'll use 10 pts for left and right padding
labelTitre.leadingAnchor.constraint(equalTo: self.leadingAnchor, constant: 10.0).isActive = true
labelTitre.trailingAnchor.constraint(equalTo: self.trailingAnchor, constant: -10.0).isActive = true

// center the label vertically (padding controlled by collectionView's layout estimated size
labelTitre.centerYAnchor.constraint(equalTo: self.centerYAnchor).isActive = true

}

required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

}

class MyMenuBarViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {

var theLabels = [
"Intro",
"Aborigenes",
"Faune",
"Flore",
"Randonnées",
"A longer label here",
"End"
]

lazy var theCollectionView : UICollectionView = {
let layout = UICollectionViewFlowLayout()
layout.scrollDirection = .horizontal
layout.minimumLineSpacing = 1.0
layout.minimumInteritemSpacing = 1.0
// note: since the labels are "auto-width-stretching", the height here defines the actual height of the cells
layout.estimatedItemSize = CGSize(width: 60, height: 28)
let cv = UICollectionView(frame: .zero, collectionViewLayout: layout)
// using lightGray for the background "fills in" the spacing, giving us "cell borders"
cv.backgroundColor = UIColor.lightGray
cv.dataSource = self
cv.delegate = self
return cv

}()

override func viewDidLoad() {
super.viewDidLoad()

self.view.backgroundColor = .yellow

// register the cell
// theCollectionView.register(MyASCell.self, forCellWithReuseIdentifier: reuseIdentifier)
theCollectionView.register(MyMenuCell.self, forCellWithReuseIdentifier: reuseIdentifier)

// we're going to add constraints, so don't use AutoresizingMask
theCollectionView.translatesAutoresizingMaskIntoConstraints = false

// add the "menu bar" to the view
self.view.addSubview(theCollectionView)

// pin collection view to left and right edges
theCollectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
theCollectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true

// pin top of collection view to topLayoutGuide
theCollectionView.topAnchor.constraint(equalTo: topLayoutGuide.bottomAnchor).isActive = true

// set height of collection view to 30
theCollectionView.heightAnchor.constraint(equalToConstant: 30.0).isActive = true

// for demonstration's sake, just add a blue view below the "menu bar"
let v = UIView(frame: CGRect.zero)
v.backgroundColor = UIColor.blue
v.translatesAutoresizingMaskIntoConstraints = false
self.view.addSubview(v)

// pin gray view to left, right, bottom of view
v.leadingAnchor.constraint(equalTo: self.view.leadingAnchor).isActive = true
v.trailingAnchor.constraint(equalTo: self.view.trailingAnchor).isActive = true
v.bottomAnchor.constraint(equalTo: self.view.bottomAnchor).isActive = true

// pin top of gray view to bottom of collection view
v.topAnchor.constraint(equalTo: theCollectionView.bottomAnchor).isActive = true

}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
// we want a 1-pt border on top, bottom and left and right edges of the collection view itself
return UIEdgeInsets(top: 1, left: 1, bottom: 1, right: 1)
}

func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}

func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return theLabels.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: reuseIdentifier, for: indexPath) as! MyMenuCell

cell.labelTitre.text = theLabels[indexPath.row]

// just simulating selection here...
cell.isSelected = indexPath.row == 0

return cell
}

}

Edit:

Here is a cap of the result from my code:

Sample Image

And a cap of the result from your code - with one line edited:

Sample Image

In your cell code, change:

addConstraintsWithFormat(format: "H:[v0]", views: labelTitre)

to:

addConstraintsWithFormat(format: "H:|-10-[v0]-10-|", views: labelTitre)

Dynamic cell width of UICollectionView depending on label width

In sizeForItemAtIndexPath return the size of the text

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout sizeForItemAtIndexPath:(NSIndexPath *)indexPath{

return [(NSString*)[arrayOfStats objectAtIndex:indexPath.row] sizeWithAttributes:NULL];
}

How to set UICollectionViewCell Width and Height programmatically

Use this method to set custom cell height width.

Make sure to add this protocols

UICollectionViewDelegate

UICollectionViewDataSource

UICollectionViewDelegateFlowLayout

If you are using swift 5 or xcode 11 and later you need to set Estimate Size to none using storyboard in order to make it work properly. If you will not set that than below code will not work as expected.

Sample Image

Swift 4 or Later

extension YourViewController: UICollectionViewDelegate {
//Write Delegate Code Here
}

extension YourViewController: UICollectionViewDataSource {
//Write DataSource Code Here
}

extension YourViewController: UICollectionViewDelegateFlowLayout {
func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> }


Related Topics



Leave a reply



Submit