2

I've been working on with a custom UICollectionViewFlowLayout to adjust the spaces between the cells so I can get a nice flow in my collectionView. But with my current code I can't figure out how I can adjust the cell sizes without "breaking" rows count. Which makes some cells think they can fit a row but they can't.

My custom flowlayout

class UserProfileTagsFlowLayout: UICollectionViewFlowLayout {
    
    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        let attributesForElementsInRect = super.layoutAttributesForElements(in: rect)
        var newAttributesForElementsInRect = [UICollectionViewLayoutAttributes]()
        
        var leftMargin: CGFloat = 0.0;
        
        for attributes in attributesForElementsInRect! {
            if (attributes.frame.origin.x == self.sectionInset.left) {
                leftMargin = self.sectionInset.left
            } else {
                var newLeftAlignedFrame = attributes.frame
                newLeftAlignedFrame.origin.x = leftMargin
                attributes.frame = newLeftAlignedFrame
            }
            leftMargin += attributes.frame.size.width + 8 // Makes the space between cells
            newAttributesForElementsInRect.append(attributes)
        }
        
        return newAttributesForElementsInRect
    }
}

So in my ViewController I've extende

extension myViewController: UICollectionViewDelegateFlowLayout {
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        let tag = tagsArray[indexPath.row]
        let font = UIFont(name: "Raleway", size: 14)!
        let size = tag.value.size(withAttributes: [NSAttributedString.Key.font: font])
        let dynamicCellWidth = size.width

        /*
          The "+ 20" gives me the padding inside the cell
        */
        return CGSize(width: dynamicCellWidth + 20, height: 35)
    }
    
    // Space between rows
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return 5
    }
    
    // Space between cells
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
        return 10
    }
}

When I try this code out i'm getting the result down in the result-section on an iPhone X. You can see the tag "Machine Learning" jumps down to a new row, because it thinks it can fit the row above. If I remove the "padding" for the cell in sizeForItem function, then I won't have this problem. But it just looks awful.

So my question is: How can I use padding on my cells without breaking the flowLayout?


So far my current result looks like this:

iPhone X:

iPhone X result

Community
  • 1
  • 1
Jacob Ahlberg
  • 2,352
  • 6
  • 22
  • 44
  • I also need to create this tag list but I am bit confused how to use it. Can you please your full article code. – Kishor Pahalwani Jan 06 '22 at 05:47
  • @KishorPahalwani I don't have access to this piece of code anymore. I didn't follow any article, I made it up myself. So I would recommend to either google a bit more or try building it yourself :) You'll have no problem building the UI for each cell. Then you can just use the code in the answer to have the correct layout. – Jacob Ahlberg Jan 10 '22 at 07:46
  • https://stackoverflow.com/questions/70618239/how-to-implement-the-tags-layout-using-uicollectionview-ios-swift can u please help me in this. – Kishor Pahalwani Jan 11 '22 at 03:05

1 Answers1

3

Maybe it will help you. I think you should check if you item stick out the collection view right inset. In layoutAttributesForElements method check this:

        let collectionViewWidth = self.collectionView?.frame.width - (self.sectionInset.right + self.sectionInset.left)

        if (attributes.frame.origin.x + attributes.frame.size.width > collectionViewWidth) {
            var newLeftAlignedFrame = attributes.frame
            newLeftAlignedFrame.origin.x = self.sectionInset.left
            attributes.frame = newLeftAlignedFrame 
        }

Updated my answer and it works for me, you can see it on screenshot

Anton Rodzik
  • 781
  • 4
  • 14