'UILabel SizeToFit Not working in UICollectionViewCell

This is my code

        class DescriptionsViewController: UIViewController {
        
        override func viewDidLoad() {
            super.viewDidLoad()
            
            collectionView.delegate = self
            collectionView.dataSource = self
            let layout = TagFlowLayout()
            layout.estimatedItemSize = CGSize(width: 140, height: 40)
            collectionView.collectionViewLayout = layout
        }
    }

    class Row {
    var attributes = [UICollectionViewLayoutAttributes]()
    var spacing: CGFloat = 0

    init(spacing: CGFloat) {
        self.spacing = spacing
    }

    func add(attribute: UICollectionViewLayoutAttributes) {
        attributes.append(attribute)
    }

    func tagLayout(collectionViewWidth: CGFloat) {
        let padding = 10
        var offset = padding
        for attribute in attributes {
            attribute.frame.origin.x = CGFloat(offset)
            offset += Int(attribute.frame.width + spacing)
        }
    }
}

    class TagFlowLayout: UICollectionViewFlowLayout {
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        guard let attributes = super.layoutAttributesForElements(in: rect) else {
            return nil
        }

        var rows = [Row]()
        var currentRowY: CGFloat = -1

        for attribute in attributes {
            if currentRowY != attribute.frame.origin.y {
                currentRowY = attribute.frame.origin.y
                rows.append(Row(spacing: 10))
            }
            rows.last?.add(attribute: attribute)
        }

        rows.forEach {
            $0.tagLayout(collectionViewWidth: collectionView?.frame.width ?? 0)
        }
        return rows.flatMap { $0.attributes }
    }
}

    extension DescriptionsViewController : UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return sourse.Ingredients.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell",for: indexPath) as? collectionViewCell else {
            
            return collectionViewCell()
        }
        
        cell.label.text = sourse.Ingredients[indexPath.row] //[indexPath.section]
        cell.label.preferredMaxLayoutWidth = collectionView.frame.width - 16
        cell.label.sizeToFit()
            
        return cell
    }
    
} // uicollectionViewDatasourse,UICollectionViewDelegate

    class collectionViewCell: UICollectionViewCell{
    
    @IBOutlet weak var label: UILabel!
    
    override func awakeFromNib() {
        super.awakeFromNib()
        
        self.layer.cornerRadius = label.frame.size.height / 2.0
        self.backgroundColor = #colorLiteral(red: 0.3647058904, green: 0.06666667014, blue: 0.9686274529, alpha: 1)
    }
} //UICollectionViewCell

I want to show like this imagebut I get like this one

The text will beyond the background color and the background color can't adaptation the text length



Solution 1:[1]

I added some code and answered my question.

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    return CGSize(width: sourse.Ingredients[indexPath.item].size(withAttributes: [NSAttributedString.Key.font : UIFont.systemFont(ofSize: 17)]).width + 25, height: 30)
}

But I think it's not best answer because this source code can detection they just add .width + 25.

Obviously this code is not "dynamic", but it does work.

Solution 2:[2]

The problem exisit in your Xib constraints. When your label cannot get the right frame, sizeToFit will not work.

If you want the label adapt to your text length, you can try.

  • Snapkit
view.contentView.addSubview(label)
label.snp.makeConstraints {
 $0.centerY.equalToSuperview()
 $0.leading.trailing.equalToSuperview().inset(customOffset)
}
  • Xib
Juset set the same constraints, ___centeY, leading, trailing___, as by SnapKit(I am not familiar how to in Xib, so sorry about no cases)
  • Original Code

this may help

class tageCollectionViewCell: UICollectionViewCell{
    
    var label: UILabel!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupView()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    func setupView() {
        label = UILabel()
        //... add your custom character
        contentView.addSubview(label)
        label.translatesAutoresizingMaskIntoConstraints = false
        let constraints = [
            label.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
            label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
            label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor)
        ]
        NSLayoutConstraint.activate(constraints)
    }
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 ouflak
Solution 2