UICollectionView dynamic cell height (Pinterest layout)
Asked Answered
G

3

10

I'm trying to achieve Pinterest layout in my app

and I used the following delegate method to achieve that and set the cell height dynamically

 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
    let boundingRect =  CGRect(x: 0, y: 0, width: self.view.frame.size.width / 2 - 20, height: CGFloat(MAXFLOAT))
    let data = articles[indexPath.row]
    let rect  = AVMakeRect(aspectRatio: (data.coverImage?.size)!, insideRect: boundingRect)
    return CGSize(width: rect.width, height: rect.height + 120) // Added 120 for a description I will add later 
}

But I got the following result:

Here

The gray background is the background of the cell, you can see that each cell has its own height (as expected) but there are extra white spaces which I don't know how to remove.

How can I fix this?

Gaona answered 17/1, 2017 at 9:17 Comment(2)
Nobody has tried this? Why is that there is no answer?Avicenna
Did you find any solution?Precaution
P
1

You can view the raywenderlich tutorial for this:

https://www.raywenderlich.com/164608/uicollectionview-custom-layout-tutorial-pinterest-2

If you want to load new data when you reach at the last cell, then you have to edit some code.

In PinterestLayout.swift, do following changes:

 guard cache.isEmpty == true, let collectionView =   collectionView else {
        return
    }

to

 guard let collectionView = collectionView else {
        return
    } 

// This file name may be differ from yours

In PhotoStreamViewController.swift, add following code:

   override func collectionView(_ collectionView:  UICollectionView, willDisplay cell: UICollectionViewCell,  forItemAt indexPath: IndexPath) {
      if (indexPath.row == photos.count - 1 ) {
     //it's your last cell

     // Add more data to the array according your requirement

     // After adding data reload collection view
        collectionView.reloadData()
        
    }
}
Precaution answered 6/9, 2018 at 12:25 Comment(0)
S
0

Your UICollectionView layout is not right. Remove cell spacing and column spacing either from storyboard or via CollectionViewDelegateFlowLayout method.

 func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
    return CGFloat()// Your Value
}

func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
     return CGFloat()// Your Value
    }
Saccharo answered 6/2, 2018 at 14:48 Comment(0)
C
0

There is how it works in my case for ChatMessageController where each cell could have different height

  1. First of all we need to use UICollectionViewFlowLayout

    extension ChatMessageController { func createLayout() -> UICollectionViewLayout {

         let layout: UICollectionViewFlowLayout = {
             let layout = UICollectionViewFlowLayout()
             let width = UIScreen.main.bounds.size.width
             layout.estimatedItemSize = CGSize(width: width, height: 80)
             return layout
         }()
    
         return layout
     }
    

    }

  2. Then in UICollectionViewCell override systemLayoutSizeFitting like this:

    override func systemLayoutSizeFitting(_ targetSize: CGSize, withHorizontalFittingPriority horizontalFittingPriority: UILayoutPriority, verticalFittingPriority: UILayoutPriority) -> CGSize { width.constant = bounds.size.width return contentView.systemLayoutSizeFitting(CGSize(width: targetSize.width, height: getHeight())) }

where getHeight is function that calculates real cell height based on content, for example:

    private func getHeight() -> CGFloat {
            let text = label.text ?? ""
            
            let constraintRect = CGSize(width: 0.75 * contentView.frame.width,
                                        height: .greatestFiniteMagnitude)
            let boundingBox = text.boundingRect(with: constraintRect,
                                                options: .usesLineFragmentOrigin,
                                                attributes: [.font: label.font as Any],
                                                context: nil)
            
            let bubbleSize = CGSize(width: boundingBox.width + d.w(30), height: boundingBox.height + d.h(30))
            
            let height = bubbleSize.height
            
            return height
        

}
Connecticut answered 31/1, 2021 at 10:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.