[ios] UICollectionView - dynamic cell height?

I just ran into this problem on a UICollectionView and the way that i solved it similar to the answer above but in a pure UICollectionView way.

  1. Create a custom UICollectionViewCell that contains whatever you will be filling it with to make it dynamic. I created its own .xib for it as it seems like the easiest approach.

  2. Add constraints in that .xib that allow for the cell to be calculated from top to bottom. The re-sizing won't work if you haven't accounted for all of the height. Say you have a view on top, then a label underneath it, and another label underneath that. You would need to connect constraints to the top of the cell to the top of that view, then the bottom of the view to the top of the first label, bottom of first label to the top of the second label, and bottom of second label to bottom of cell.

  3. Load the .xib into the viewcontroller and register it with the collectionView on viewDidLoad

    let nib = UINib(nibName: CustomCellName, bundle: nil)
    self.collectionView!.registerNib(nib, forCellWithReuseIdentifier: "customCellID")`
    
  4. Load a second copy of that xib into the class and store it as a property so you can use it to determine the size of what that cell should be

    let sizingNibNew = NSBundle.mainBundle().loadNibNamed(CustomCellName, owner: CustomCellName.self, options: nil) as NSArray
    self.sizingNibNew = (sizingNibNew.objectAtIndex(0) as? CustomViewCell)!
    
  5. Implement the UICollectionViewFlowLayoutDelegate in your view controller. The method that matters is called sizeForItemAtIndexPath. Inside that method you will need to pull the data from the datasource that is associated with that cell from the indexPath. Then configure the sizingCell and call preferredLayoutSizeFittingSize. The method returns a CGSize which will consist of the width minus the content insets and the height that is returned from self.sizingCell.preferredLayoutSizeFittingSize(targetSize).

    override func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
        guard let data = datasourceArray?[indexPath.item] else {
            return CGSizeZero
        }
        let sectionInset = self.collectionView?.collectionViewLayout.sectionInset
        let widthToSubtract = sectionInset!.left + sectionInset!.right
    
        let requiredWidth = collectionView.bounds.size.width
    
    
        let targetSize = CGSize(width: requiredWidth, height: 0)
    
        sizingNibNew.configureCell(data as! CustomCellData, delegate: self)
        let adequateSize = self.sizingNibNew.preferredLayoutSizeFittingSize(targetSize)
        return CGSize(width: (self.collectionView?.bounds.width)! - widthToSubtract, height: adequateSize.height)
     }
    
  6. In the class of the custom cell itself you will need to override awakeFromNib and tell the contentView that its size needs to be flexible

     override func awakeFromNib() {
        super.awakeFromNib()
        self.contentView.autoresizingMask = [UIViewAutoresizing.FlexibleHeight]
     }
    
  7. In the custom cell override layoutSubviews

     override func layoutSubviews() {
       self.layoutIfNeeded()
      }
    
  8. In the class of the custom cell implement preferredLayoutSizeFittingSize. This is where you will need to do any trickery on the items that are being laid out. If its a label you will need to tell it what its preferredMaxWidth should be.

    func preferredLayoutSizeFittingSize(_ targetSize: CGSize)-> CGSize {
    
        let originalFrame = self.frame
        let originalPreferredMaxLayoutWidth = self.label.preferredMaxLayoutWidth
    
    
        var frame = self.frame
        frame.size = targetSize
        self.frame = frame
    
        self.setNeedsLayout()
        self.layoutIfNeeded()
        self.label.preferredMaxLayoutWidth = self.questionLabel.bounds.size.width
    
    
        // calling this tells the cell to figure out a size for it based on the current items set
        let computedSize = self.systemLayoutSizeFittingSize(UILayoutFittingCompressedSize)
    
        let newSize = CGSize(width:targetSize.width, height:computedSize.height)
    
        self.frame = originalFrame
        self.questionLabel.preferredMaxLayoutWidth = originalPreferredMaxLayoutWidth
    
        return newSize
    }
    

All those steps should give you the correct sizes. If your getting 0 or other funky numbers than you haven't set up your constraints properly.

Examples related to ios

Adding a UISegmentedControl to UITableView Crop image to specified size and picture location Undefined Symbols error when integrating Apptentive iOS SDK via Cocoapods Keep placeholder text in UITextField on input in IOS Accessing AppDelegate from framework? Autoresize View When SubViews are Added Warp \ bend effect on a UIView? Speech input for visually impaired users without the need to tap the screen make UITableViewCell selectable only while editing Xcode 12, building for iOS Simulator, but linking in object file built for iOS, for architecture arm64

Examples related to swift

Make a VStack fill the width of the screen in SwiftUI Xcode 10.2.1 Command PhaseScriptExecution failed with a nonzero exit code Command CompileSwift failed with a nonzero exit code in Xcode 10 Convert Json string to Json object in Swift 4 iOS Swift - Get the Current Local Time and Date Timestamp Xcode 9 Swift Language Version (SWIFT_VERSION) How do I use Safe Area Layout programmatically? How can I use String substring in Swift 4? 'substring(to:)' is deprecated: Please use String slicing subscript with a 'partial range from' operator Safe Area of Xcode 9 The use of Swift 3 @objc inference in Swift 4 mode is deprecated?

Examples related to uicollectionview

How to set UICollectionViewCell Width and Height programmatically How to make a simple collection view with Swift How to set cell spacing and UICollectionView - UICollectionViewFlowLayout size ratio? UICollectionView - dynamic cell height? UICollectionView Self Sizing Cells with Auto Layout Fatal error: unexpectedly found nil while unwrapping an Optional values Paging UICollectionView by cells, not screen UICollectionView - Horizontal scroll, horizontal layout? UICollectionView current visible cell index Creating a UICollectionView programmatically