Search code examples
iosswiftuilabelcollectionview

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 image but I get like this one

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


Solution

  • 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.