Swift
Swift

Reputation: 1184

How to change CollectionView cell width according to label text in swift

I need to change collectionview cell width according to its label text like this

enter image description here

for that i have given collectionview constraints

top, leading, trailing, = 10 height = 80

in cell i have placed label inside uiview, i have placed uiview because i need to give corner radious

and code

class SearchFilterVC: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource {


var textArray = ["hbdhwebhj", "behgwfhjewgbkfjbe", "hbhjs", "bdhsbfhegu", "gwdgyqwuguq"]


@IBOutlet weak var collectionView: UICollectionView!
override func viewDidLoad() {
    super.viewDidLoad()

           let layout = UICollectionViewFlowLayout()
            layout.scrollDirection = .horizontal
            layout.minimumInteritemSpacing = 0
            layout.minimumLineSpacing = 5
            self.collectionView.collectionViewLayout = layout        
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
    return textArray.count
}

func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SearchFilterCollectionViewCell", for: indexPath as IndexPath) as! SearchFilterCollectionViewCell
       
    
    cell.textLabel.text = textArray[indexPath.row]
        return cell
}
}

edit:

enter image description here

o/p

enter image description here

how to over come from this issue, please do help with code

Upvotes: 2

Views: 5157

Answers (1)

Sandeep Bhandari
Sandeep Bhandari

Reputation: 20379

All items in your collectionView are taking the exact same size because you have specified layout.itemSize for your collectionView's flow layout

remove layout.itemSize = CGSize(width: self.collectionView.frame.size.width / 2, height: 80)

Other issues in code:

  1. layout.invalidateLayout() is unnecessary in ViewDidLoad
  2. if let layout = self.collectionView.collectionViewLayout as? UICollectionViewFlowLayout { to set minimumInteritemSpacing and minimumLineSpacing is unnecessary, in a statement just above it you have created let layout = UICollectionViewFlowLayout() why dont you simply set minimumInteritemSpacing and minimumLineSpacing there itself? Why use additional if let?

Simply write

        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        layout.minimumInteritemSpacing = 0
        layout.minimumLineSpacing = 5
        self.collectionView.collectionViewLayout = layout

You need not specify item size, Collection view flow layout is set to be horizontal in nature, so by default each item will take the same height as the collection view height and if you have only one label inside the cell and if you have set autolayout constraint properly, label's intrinsic content size will ensure cell gets proper width

enter image description here

And forwhatever reason if you decide to wrap the label inside a UIView logic above holds good, as long as you set the label's autolayout constraint right, lablel's intrinsic content size will set the width of the containerView and which will in turn contribute to set the cell's width appropriately,

Here cell has background color of red, container view has orange and label has no background color, I have added leading and trailing spacing between cell and view as 10, and label and container view has leading and trailing space as 5

enter image description here

EDIT:

As OP is asking for constraints between container view, label and cell, I am updating answer to reflect the same

enter image description here

Clearly

  - - - - - - - - - - - - Cell - - - - - - - - - - - - - - - -
|       - - - - - - - - Container View - - - - - - - -          |
|     |                      |5                          |      |   
|-10- |-5-                  Label                     -5-| -10- |   
|     |                      |5                          |      |
|       - - - - - - - - - - - - - - - - - - - - - - - - -       |
|                                                               |
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  

You can add top and bottom constraint between cell and conatiner if you need, but I have kept container view vertically center to cell

How it works?

Label has intrinsic content-size which it gets from the text set to it, View does gets its intrinsic size based on the size of its subview, because there are no subviews in your container view, it gets its size from label and clearly whatever the size label returns view adds 10 to width and 10 to height ( 5 leading, 5 trailing, 5 top and 5 bottom) finally cell gets its size from its subviews, because there is only one subview (container view) it gets width from container view and for height it gets its height from collection view (as subviews dont provide enough data to calculate its height)

And if for some reason (might be because of some other constraints you have set knowingly / unknowingly like adding width constraint on container view) label is not taking its intrinsic content size correctly, you can always set setContentCompressionResistancePriority and setContentHuggingPriority on label to high in your cell's awake from nib

override func awakeFromNib() {
        super.awakeFromNib()
        self.label.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
        self.label.setContentHuggingPriority(.defaultHigh, for: .horizontal)
 }

Though this shouldnt be needed in usual case, if this is needed to get correct intrinsic size, there must be some other constraints which are preventing the label to take its proper implicit intrinsic content size, if I were in your position would rather check and fix it first. Nonetheless cant debug further with limited code you have provided.

EDIT 2:

Did not realize that OP is using custom instance of UICollectionViewFlowLayout and has not set estimatedItemSize property to automaticSize

        let layout = UICollectionViewFlowLayout()
        layout.scrollDirection = .horizontal
        layout.minimumInteritemSpacing = 0
        layout.minimumLineSpacing = 5
        layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize
        self.collectionView.collectionViewLayout = layout

Upvotes: 6

Related Questions